Giter Site home page Giter Site logo

copy's People

Contributors

goldenstein64 avatar

Watchers

 avatar

copy's Issues

Copy:CreateContext

A version of Copy:BehaveAs that allows for broader control over how values are copied. I would probably go for a shorter function name though, like Copy:Contextualize (which isn't even shorter).

Given:

local value1 = {
  key = "value 1"
}

local value2 = {
  key = "value 2"
}

local value3 = {
  key = "value 3"
}

local some = {
  key1 = value1,
  key2 = value2,
  key3 = value3,
}

Instead of:

local base = {
  key1 = Copy:BehaveAs("replace", value1),
  key2 = Copy:BehaveAs("replace", value2),
  key3 = Copy:BehaveAs("replace", value3),
}

Copy:Extend(some, base)

You can do:

local context = {
  Values = "replace",
}

local base = Copy:CreateContext(context, some)

Copy:Extend(some, base)

In this example you can just do this, but it seems really hacky:

Copy.GlobalContext.Values = "replace"
Copy:Extend(some, some)
Copy.GlobalContext.Values = "default"

Test:

local value1 = { key = "value 1" }
local value2 = { key = "value 2" }
local value3 = { key = "value 3" }

it("can create contexts", function()
  local some = {
    key1 = value1,
    key2 = value2,
    key3 = value3,
  }

  local context = {
    Values = "replace"
  }

  local base = Copy:CreateContext(context, some)

  Copy:Extend(some, base)

  for i, value in ipairs{value1, value2, value3} do
    local usedKey = string.format("key%d", i)
    local subValue = string.format("value %d", i)
    local subSome = some[usedKey]

    expect(subSome).to.be.a("table")
    expect(subSome).to.never.equal(value)
    expect(subSome.key).to.equal(subValue)
  end
end)

A possibly more intuitive behavior could be making Copy:CreateContext apply to the root value as well as its sub-values. I feel like that would be complicated though because there would be extra logic for what context the root value is currently in, and that could be confusing/unwanted behavior too.

This would only be useful for cases where transformers can directly affect sub-values. This is only true for "reconcile" and "replace", so there aren't enough transformers for this to be applied to its full effect.

Documentation clean-up

  • When to use Copy: clarify that functions can't be copied at the end.

  • API Reference: Describe what types each behavior supports

  • Clarify that Copy.Transform accepts any value in a key-value mapping, and that it's not recommended to use them as keys.

  • "These functions can be found in the test directory found here." -> "These functions can be found in the test directory."

  • Symbol API: Turn Symbol() into a function type, Symbol(T) -> (boolean, T).

  • Clarify that functions used as symbols can be called "symbol functions".

  • Reinforce that you have to register a symbol function to Copy.SymbolMap before using it.

  • For the function parameters, "the old value's field" -> "the old value"

__copy metatable field

It might be more ergonomic to use metatables to describe how table sub-values are copied instead of Copy:CreateContext or Copy:BehaveAs. It would be exactly what a metatable is used for, it would have exactly the same functionality as Copy:BehaveAs, it would stay connected to the normal table (or multiple tables), and it would stay out of the way very easily.

it("can use the '__copy' metatable field", function()
  local sub = {
    key = "some value"
  }

  local some = {
    owned = sub,
    shared = sub
  }

  local mt = {}

  -- __copy represents a mapping of keys to behaviors/symbols for sub-values
  -- omitted keys are treated as default
  mt.__copy = {
    shared = "set"
  }

  setmetatable(some, mt)

  local new = Copy(some)

  expect(new).to.never.equal(owned)
  expect(new.shared).to.equal(some.shared)
  expect(new.owned).to.never.equal(new.owned)
end)

It might also make classes easier to implement?

local someClass = {}

local prototype = {
  owned = {},
  shared = {},
  key = "value"
}

function prototype:Method(name)
  return self.owned[name] or self.shared[name]
end

local mt = {}

mt.__copy = {
  shared = "set"
}

setmetatable(prototype, mt)

someClass.prototype = prototype

function someClass.new()
  return Copy(someClass.prototype)
end

return someClass

Copy.TempTransform

A table that gets flushed after a copy call is finished. We can then make Copy.Transform persistent after every call and make TempTransform use __index on it.

it("has a persistent Transform", function()
  Copy.Transform["value"] = "some other value"

  Copy(nil)

  expect(Copy.Transform["value"]).to.equal("some other value")
end)

it("has a temporary Transform", function()
  Copy.TempTransform["value"] = "some other value"

  Copy(nil)

  expect(Copy.TempTransform["value"]).to.equal(nil)
end)

This would affect every file that uses Transform, since we are changing the behavior of an existing namespace.

Complete the usage-guide index

The only thing I can provide in the usage guide is use cases, not common properties of situations where Copy would be a good solution. Although Copy covers a novel use case, Lua has a programming pattern that overlaps with where Copy is most extensible and useful: factory functions.

-- where Copy can do this,
local prototype = {
  property = "value"
}

local obj = Copy(prototype)

-- factory functions can do it just as easily!
-- and arguments can be added 
-- to change the table's configuration:
local function makeObj(...)
  return {
    property = "value",
    ...
  }
end

local obj = makeObj(...)

A well-structured factory function will always be better than a well-structured application of Copy because it's simpler and clearer. Even if the table is huge, you still have to write the factory function only once.

Maybe a place where Copy would be better is when the prototype is programmatically created:

local prototype = {}
for _, child in ipairs(script:GetChildren()) do
  prototype[child.Name] = child:GetAttribute("Value")
end

local obj = Copy(prototype)

-- vs

local function makeObj()
  local obj = {}
  for _, child in ipairs(script:GetChildren()) do
    obj[child.Name] = child:GetAttribute("Value")
  end
  return obj
end

local obj = makeObj()

It would be more performance-intensive to use a factory function to copy each child's value than it would be to Copy() it.

So far, my conclusion is that factory functions become as complex as the table it constructs. However, the complexity of Copy() stays the same, and the responsible prototype carries all the complexity. Copy() can be combined with factory functions to create a different pathway to the same result; maybe it's simpler to start from a copy and modify it instead of starting from an empty table or a table construction.

Create a "copyObject" internally upon call

Possibly required infrastructure for #7

Acts as an internal state the way Instances.ApplyTransform does. It would make some of the code simpler instead of passing behaviors, contexts, etc. and making the argument list too long.

Basically my excuse to use a structure similar to RaycastParams

Behavior Assertions per Type

If a given value isn't compatible with the given transformer, it can throw an error.

e.g.

local some = "value"

expect(function()
    Copy:BehaveAs("replace", some)
end).to.throw()

Purely optional, a flag should be made for it.

If no transformer matches among multiple, it should throw an error as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.