representable 2.3.0 → 2.4.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +47 -0
- data/Gemfile +5 -0
- data/README.md +33 -0
- data/lib/representable.rb +60 -73
- data/lib/representable/binding.rb +37 -194
- data/lib/representable/cached.rb +10 -46
- data/lib/representable/coercion.rb +8 -8
- data/lib/representable/config.rb +15 -75
- data/lib/representable/debug.rb +41 -59
- data/lib/representable/declarative.rb +34 -53
- data/lib/representable/decorator.rb +11 -40
- data/lib/representable/definition.rb +14 -15
- data/lib/representable/deprecations.rb +90 -0
- data/lib/representable/deserializer.rb +87 -82
- data/lib/representable/for_collection.rb +5 -3
- data/lib/representable/hash.rb +5 -3
- data/lib/representable/hash/binding.rb +6 -15
- data/lib/representable/hash/collection.rb +10 -6
- data/lib/representable/hash_methods.rb +5 -5
- data/lib/representable/insert.rb +31 -0
- data/lib/representable/json.rb +7 -3
- data/lib/representable/json/hash.rb +1 -1
- data/lib/representable/object/binding.rb +5 -5
- data/lib/representable/parse_strategies.rb +37 -3
- data/lib/representable/pipeline.rb +37 -5
- data/lib/representable/pipeline_factories.rb +88 -0
- data/lib/representable/serializer.rb +38 -44
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml.rb +4 -0
- data/lib/representable/xml/binding.rb +25 -31
- data/lib/representable/xml/collection.rb +5 -3
- data/lib/representable/xml/hash.rb +7 -2
- data/lib/representable/yaml.rb +6 -3
- data/lib/representable/yaml/binding.rb +4 -4
- data/representable.gemspec +3 -3
- data/test/---deserialize-pipeline_test.rb +37 -0
- data/test/binding_test.rb +7 -7
- data/test/cached_test.rb +31 -19
- data/test/coercion_test.rb +2 -2
- data/test/config/inherit_test.rb +13 -12
- data/test/config_test.rb +12 -67
- data/test/decorator_test.rb +4 -5
- data/test/default_test.rb +34 -0
- data/test/defaults_options_test.rb +93 -0
- data/test/definition_test.rb +19 -39
- data/test/exec_context_test.rb +1 -1
- data/test/filter_test.rb +18 -20
- data/test/getter_setter_test.rb +1 -8
- data/test/hash_bindings_test.rb +13 -13
- data/test/heritage_test.rb +62 -0
- data/test/if_test.rb +1 -0
- data/test/inherit_test.rb +5 -3
- data/test/instance_test.rb +3 -4
- data/test/json_test.rb +3 -59
- data/test/lonely_test.rb +47 -3
- data/test/nested_test.rb +8 -2
- data/test/pipeline_test.rb +259 -0
- data/test/populator_test.rb +76 -0
- data/test/realistic_benchmark.rb +39 -7
- data/test/render_nil_test.rb +21 -0
- data/test/represent_test.rb +2 -2
- data/test/representable_test.rb +33 -103
- data/test/schema_test.rb +5 -15
- data/test/serialize_deserialize_test.rb +2 -2
- data/test/skip_test.rb +1 -1
- data/test/test_helper.rb +6 -0
- data/test/uncategorized_test.rb +67 -0
- data/test/xml_bindings_test.rb +6 -6
- data/test/xml_test.rb +6 -6
- metadata +33 -13
- data/lib/representable/apply.rb +0 -13
- data/lib/representable/inheritable.rb +0 -71
- data/lib/representable/mapper.rb +0 -83
- data/lib/representable/populator.rb +0 -56
- data/test/inheritable_test.rb +0 -97
data/lib/representable/hash.rb
CHANGED
@@ -14,14 +14,16 @@ module Representable
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
17
|
module ClassMethods
|
18
|
+
def format_engine
|
19
|
+
Representable::Hash
|
20
|
+
end
|
21
|
+
|
19
22
|
def collection_representer_class
|
20
23
|
Collection
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
|
-
|
25
27
|
def from_hash(data, options={}, binding_builder=Binding)
|
26
28
|
data = filter_wrap(data, options)
|
27
29
|
|
@@ -31,7 +33,7 @@ module Representable
|
|
31
33
|
def to_hash(options={}, binding_builder=Binding)
|
32
34
|
hash = create_representation_with({}, options, binding_builder)
|
33
35
|
|
34
|
-
return hash if options[:wrap] == false
|
36
|
+
return hash if options[:wrap] == false
|
35
37
|
return hash unless wrap = options[:wrap] || representation_wrap(options)
|
36
38
|
|
37
39
|
{wrap => hash}
|
@@ -3,20 +3,16 @@ require 'representable/binding'
|
|
3
3
|
module Representable
|
4
4
|
module Hash
|
5
5
|
class Binding < Representable::Binding
|
6
|
-
def self.build_for(definition
|
7
|
-
|
8
|
-
|
9
|
-
return Hash.new(definition, *args) if definition.hash?
|
10
|
-
new(definition, *args)
|
6
|
+
def self.build_for(definition)
|
7
|
+
return Collection.new(definition) if definition.array?
|
8
|
+
new(definition)
|
11
9
|
end
|
12
10
|
|
13
|
-
def read(hash)
|
14
|
-
|
15
|
-
|
16
|
-
hash[as] # fragment
|
11
|
+
def read(hash, as)
|
12
|
+
hash.has_key?(as) ? hash[as] : FragmentNotFound
|
17
13
|
end
|
18
14
|
|
19
|
-
def write(hash, fragment)
|
15
|
+
def write(hash, fragment, as)
|
20
16
|
hash[as] = fragment
|
21
17
|
end
|
22
18
|
|
@@ -31,11 +27,6 @@ module Representable
|
|
31
27
|
class Collection < self
|
32
28
|
include Representable::Binding::Collection
|
33
29
|
end
|
34
|
-
|
35
|
-
|
36
|
-
class Hash < self
|
37
|
-
include Representable::Binding::Hash
|
38
|
-
end
|
39
30
|
end
|
40
31
|
end
|
41
32
|
end
|
@@ -6,7 +6,7 @@ module Representable::Hash
|
|
6
6
|
base.class_eval do
|
7
7
|
include Representable::Hash
|
8
8
|
extend ClassMethods
|
9
|
-
|
9
|
+
property(:_self, {:collection => true})
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -19,14 +19,18 @@ module Representable::Hash
|
|
19
19
|
|
20
20
|
|
21
21
|
def create_representation_with(doc, options, format)
|
22
|
-
bin =
|
23
|
-
|
22
|
+
bin = representable_bindings_for(format, options).first
|
23
|
+
|
24
|
+
Collect[*bin.default_render_fragment_functions].
|
25
|
+
(represented, {doc: doc, fragment: represented, user_options: options, binding: bin, represented: represented})
|
24
26
|
end
|
25
27
|
|
26
28
|
def update_properties_from(doc, options, format)
|
27
|
-
bin =
|
28
|
-
|
29
|
-
value =
|
29
|
+
bin = representable_bindings_for(format, options).first
|
30
|
+
|
31
|
+
value = Collect[*bin.default_parse_fragment_functions].
|
32
|
+
(doc, fragment: doc, document: doc, user_options: options, binding: bin, represented: represented)
|
33
|
+
|
30
34
|
represented.replace(value)
|
31
35
|
end
|
32
36
|
end
|
@@ -2,17 +2,17 @@ module Representable
|
|
2
2
|
module HashMethods
|
3
3
|
def create_representation_with(doc, options, format)
|
4
4
|
hash = filter_keys_for!(represented, options) # FIXME: this modifies options and replicates logic from Representable.
|
5
|
-
bin =
|
5
|
+
bin = representable_map(options, format).first
|
6
6
|
|
7
|
-
bin.
|
7
|
+
Collect::Hash[*bin.default_render_fragment_functions].extend(Pipeline::Debug).(hash, {doc: doc, user_options: options, binding: bin, represented: represented, decorator: self})
|
8
8
|
end
|
9
9
|
|
10
10
|
def update_properties_from(doc, options, format)
|
11
11
|
hash = filter_keys_for!(doc, options)
|
12
|
-
bin =
|
12
|
+
bin = representable_map(options, format).first
|
13
|
+
|
14
|
+
value = Collect::Hash[*bin.default_parse_fragment_functions].(hash, fragment: hash, document: doc, binding: bin, represented: represented, user_options: options, decorator: self)
|
13
15
|
|
14
|
-
value = Deserializer::Hash.new(bin).call(hash)
|
15
|
-
# value = bin.deserialize_from(hash)
|
16
16
|
represented.replace(value)
|
17
17
|
end
|
18
18
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Representable
|
2
|
+
Pipeline.class_eval do # FIXME: this doesn't define Function in Pipeline.
|
3
|
+
module Function
|
4
|
+
class Insert
|
5
|
+
def call(arr, func, options)
|
6
|
+
arr = arr.dup
|
7
|
+
delete!(arr, func) if options[:delete]
|
8
|
+
replace!(arr, options[:replace], func) if options[:replace]
|
9
|
+
arr
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def replace!(arr, old_func, new_func)
|
14
|
+
arr.each_with_index { |func, index|
|
15
|
+
if func.is_a?(Collect)
|
16
|
+
arr[index] = Collect[*Pipeline::Insert.(func, new_func, replace: old_func)]
|
17
|
+
end
|
18
|
+
|
19
|
+
arr[index] = new_func if old_func.is_a?(Proc)? (func==old_func) : old_func.instance_of?(func.class)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete!(arr, func)
|
24
|
+
arr.delete(func)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Pipeline::Insert = Function::Insert.new
|
31
|
+
end
|
data/lib/representable/json.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "representable/hash"
|
2
|
+
require "representable/json/collection"
|
3
3
|
|
4
4
|
begin
|
5
|
-
require
|
5
|
+
require "multi_json"
|
6
6
|
rescue LoadError => _
|
7
7
|
abort "Missing dependency 'multi_json' for Representable::JSON. See dependencies section in README.md for details."
|
8
8
|
end
|
@@ -23,6 +23,10 @@ module Representable
|
|
23
23
|
|
24
24
|
|
25
25
|
module ClassMethods
|
26
|
+
def format_engine
|
27
|
+
Representable::Hash
|
28
|
+
end
|
29
|
+
|
26
30
|
def collection_representer_class
|
27
31
|
JSON::Collection
|
28
32
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
module Representable
|
2
2
|
module Object
|
3
3
|
class Binding < Representable::Binding
|
4
|
-
def self.build_for(definition
|
5
|
-
return Collection.new(definition
|
6
|
-
new(definition
|
4
|
+
def self.build_for(definition) # TODO: remove default arg.
|
5
|
+
return Collection.new(definition) if definition.array?
|
6
|
+
new(definition)
|
7
7
|
end
|
8
8
|
|
9
|
-
def read(hash)
|
9
|
+
def read(hash, as)
|
10
10
|
fragment = hash.send(as) # :getter? no, that's for parsing!
|
11
11
|
|
12
12
|
return FragmentNotFound if fragment.nil? and typed?
|
13
13
|
fragment
|
14
14
|
end
|
15
15
|
|
16
|
-
def write(hash, fragment)
|
16
|
+
def write(hash, fragment, as)
|
17
17
|
true
|
18
18
|
end
|
19
19
|
|
@@ -1,4 +1,36 @@
|
|
1
1
|
module Representable
|
2
|
+
class Populator
|
3
|
+
FindOrInstantiate = ->(input, options) {
|
4
|
+
AssignFragment.(input, options)
|
5
|
+
|
6
|
+
binding = options[:binding]
|
7
|
+
|
8
|
+
object_class = binding[:class].(input, options)
|
9
|
+
object = object_class.find_by(id: input["id"]) || object_class.new
|
10
|
+
if options[:binding].array?
|
11
|
+
# represented.songs[i] = model
|
12
|
+
options[:represented].send(binding.getter)[options[:index]] = object
|
13
|
+
else
|
14
|
+
# represented.song = model
|
15
|
+
options[:represented].send(binding.setter, object)
|
16
|
+
end
|
17
|
+
|
18
|
+
object
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.apply!(options)
|
22
|
+
return unless populator = options[:populator]
|
23
|
+
|
24
|
+
options[:parse_pipeline] = ->(input, options) do
|
25
|
+
pipeline = Pipeline[*parse_functions] # TODO: AssignFragment
|
26
|
+
pipeline = Pipeline::Insert.(pipeline, Set, delete: true) # remove the setter function.
|
27
|
+
pipeline = Pipeline::Insert.(pipeline, populator, replace: CreateObject) # let the populator do CreateObject's job.
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
FindOrInstantiate = Populator::FindOrInstantiate
|
33
|
+
|
2
34
|
# Parse strategies are just a combination of representable's options. They save you from memoizing the
|
3
35
|
# necessary parameters.
|
4
36
|
#
|
@@ -7,6 +39,8 @@ module Representable
|
|
7
39
|
def self.apply!(options)
|
8
40
|
return unless strategy = options[:parse_strategy]
|
9
41
|
|
42
|
+
warn "[Representable] :parse_strategy is deprecated. Please use a populator."
|
43
|
+
|
10
44
|
strategy = :proc if strategy.is_a?(::Proc)
|
11
45
|
|
12
46
|
parse_strategies[strategy].apply!(name, options)
|
@@ -33,11 +67,11 @@ module Representable
|
|
33
67
|
|
34
68
|
class Sync
|
35
69
|
def self.apply!(name, options)
|
36
|
-
options[:setter] = lambda {
|
70
|
+
options[:setter] = lambda { |*args| }
|
37
71
|
options[:pass_options] = true
|
38
72
|
options[:instance] = options[:collection] ?
|
39
|
-
lambda { |fragment, i, options| options.binding.get[i] } :
|
40
|
-
lambda { |fragment, options| options.binding.get }
|
73
|
+
lambda { |fragment, i, options| options.binding.get(represented: options.represented)[i] } :
|
74
|
+
lambda { |fragment, options| options.binding.get(represented: options.represented) }
|
41
75
|
end
|
42
76
|
end
|
43
77
|
|
@@ -1,14 +1,46 @@
|
|
1
1
|
module Representable
|
2
2
|
# Allows to implement a pipeline of filters where a value gets passed in and the result gets
|
3
3
|
# passed to the next callable object.
|
4
|
-
#
|
5
|
-
# Note: this is still experimental.
|
6
4
|
class Pipeline < Array
|
7
5
|
include Uber::Callable
|
8
|
-
# include Representable::Cloneable
|
9
6
|
|
10
|
-
|
11
|
-
|
7
|
+
Stop = Class.new
|
8
|
+
|
9
|
+
# options is mutuable.
|
10
|
+
def call(input, options)
|
11
|
+
inject(input) do |memo, block|
|
12
|
+
res = evaluate(block, memo, options)
|
13
|
+
return(Stop)if Stop == res
|
14
|
+
res
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def evaluate(block, input, options)
|
20
|
+
block.call(input, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Collect applies a pipeline to each element of input.
|
26
|
+
class Collect < Pipeline
|
27
|
+
# when stop, the element is skipped. (should that be Skip then?)
|
28
|
+
def call(input, options)
|
29
|
+
arr = []
|
30
|
+
input.each_with_index do |item_fragment, i|
|
31
|
+
result = super(item_fragment, options.merge(index: i)) # DISCUSS: NO :fragment set.
|
32
|
+
Pipeline::Stop == result ? next : arr << result
|
33
|
+
end
|
34
|
+
arr
|
35
|
+
end
|
36
|
+
|
37
|
+
class Hash < Pipeline
|
38
|
+
def call(input, options)
|
39
|
+
{}.tap do |hsh|
|
40
|
+
input.each { |key, item_fragment|
|
41
|
+
hsh[key] = super(item_fragment, options) }# DISCUSS: NO :fragment set.
|
42
|
+
end
|
43
|
+
end
|
12
44
|
end
|
13
45
|
end
|
14
46
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# NOTE: this might become a separate class, that's why it's in a separate file.
|
2
|
+
module Representable
|
3
|
+
module Binding::Factories
|
4
|
+
def pipeline_for(name, input, options)
|
5
|
+
return yield unless proc = @definition[name]
|
6
|
+
# proc.(self, options)
|
7
|
+
instance_exec(input, options, &proc)
|
8
|
+
end
|
9
|
+
|
10
|
+
# i decided not to use polymorphism here for the sake of clarity.
|
11
|
+
def collect_for(item_functions)
|
12
|
+
return [Collect[*item_functions]] if array?
|
13
|
+
return [Collect::Hash[*item_functions]] if self[:hash]
|
14
|
+
item_functions
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_functions
|
18
|
+
[*default_parse_init_functions, *collect_for(default_parse_fragment_functions), *default_post_functions]
|
19
|
+
end
|
20
|
+
|
21
|
+
# DISCUSS: StopOnNil, before collect
|
22
|
+
def render_functions
|
23
|
+
[*default_render_init_functions, *collect_for(default_render_fragment_functions), WriteFragment]
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_render_fragment_functions
|
27
|
+
functions = []
|
28
|
+
functions << SkipRender if self[:skip_render]
|
29
|
+
if typed? # TODO: allow prepare regardless of :extend, which makes it independent of typed?
|
30
|
+
if self[:prepare]
|
31
|
+
functions << Prepare
|
32
|
+
end
|
33
|
+
# functions << (self[:prepare] ? Prepare : Decorate)
|
34
|
+
end
|
35
|
+
functions << Decorate if self[:extend] and !self[:prepare]
|
36
|
+
if representable?
|
37
|
+
functions << (self[:serialize] ? Serializer : Serialize)
|
38
|
+
end
|
39
|
+
functions
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_render_init_functions
|
43
|
+
functions = []
|
44
|
+
functions << Stop if self[:readable]==false
|
45
|
+
functions << StopOnExcluded
|
46
|
+
functions << If if self[:if]
|
47
|
+
functions << (self[:getter] ? Getter : Get)
|
48
|
+
functions << Writer if self[:writer]
|
49
|
+
functions << RenderFilter if self[:render_filter].any?
|
50
|
+
functions << RenderDefault if has_default?
|
51
|
+
functions << StopOnSkipable
|
52
|
+
functions << (self[:as] ? AssignAs : AssignName)
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_parse_init_functions
|
56
|
+
functions = []
|
57
|
+
functions << Stop if self[:writeable]==false
|
58
|
+
functions << StopOnExcluded
|
59
|
+
functions << If if self[:if]
|
60
|
+
functions << (self[:as] ? AssignAs : AssignName)
|
61
|
+
functions << (self[:reader] ? Reader : ReadFragment)
|
62
|
+
functions << (has_default? ? Default : StopOnNotFound)
|
63
|
+
functions << OverwriteOnNil # include StopOnNil if you don't want to erase things.
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_parse_fragment_functions
|
67
|
+
functions = []
|
68
|
+
functions << SkipParse if self[:skip_parse]
|
69
|
+
|
70
|
+
if typed?
|
71
|
+
functions << CreateObject
|
72
|
+
functions << Prepare if self[:prepare]
|
73
|
+
functions << Decorate if self[:extend]
|
74
|
+
if representable?
|
75
|
+
functions << (self[:deserialize] ? Deserializer : Deserialize)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
functions
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_post_functions
|
83
|
+
funcs = []
|
84
|
+
funcs << ParseFilter if self[:parse_filter].any?
|
85
|
+
funcs << (self[:setter] ? Setter : Set)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -1,60 +1,54 @@
|
|
1
|
-
require "representable/deserializer"
|
2
|
-
|
3
1
|
module Representable
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
return object if object.nil? # DISCUSS: move to Object#serialize ?
|
2
|
+
Getter = ->(input, options) do
|
3
|
+
options[:binding].evaluate_option(:getter, input, options)
|
4
|
+
end
|
8
5
|
|
9
|
-
|
10
|
-
end
|
6
|
+
Get = ->(input, options) { options[:binding].send(:exec_context, options).send(options[:binding].getter) }
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
Writer = ->(input, options) do
|
9
|
+
options[:binding].evaluate_option(:writer, input, options)
|
10
|
+
Pipeline::Stop
|
11
|
+
end
|
15
12
|
|
16
|
-
|
17
|
-
|
13
|
+
# TODO: evaluate this, if we need this.
|
14
|
+
RenderDefault = ->(input, options) do
|
15
|
+
binding = options[:binding]
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
object = prepare(object)
|
17
|
+
binding.skipable_empty_value?(input) ? binding[:default] : input
|
18
|
+
end
|
22
19
|
|
23
|
-
|
20
|
+
StopOnSkipable = ->(input, options) do
|
21
|
+
options[:binding].send(:skipable_empty_value?, input) ? Pipeline::Stop : input
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
24
|
+
RenderFilter = ->(input, options) do
|
25
|
+
options[:binding][:render_filter].(input, options)
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
object.send(@binding.serialize_method, user_options)
|
34
|
-
end
|
28
|
+
SkipRender = ->(input, options) do
|
29
|
+
options[:binding].evaluate_option(:skip_render, input, options) ? Pipeline::Stop : input
|
30
|
+
end
|
35
31
|
|
32
|
+
Serializer = ->(input, options) do
|
33
|
+
return if input.nil? # DISCUSS: how can we prevent that?
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
collection = [] # TODO: unify with Deserializer::Collection.
|
35
|
+
options[:binding].evaluate_option(:serialize, input, options)
|
36
|
+
end
|
40
37
|
|
41
|
-
|
42
|
-
|
38
|
+
Serialize = ->(input, options) do
|
39
|
+
return if input.nil? # DISCUSS: how can we prevent that?
|
40
|
+
binding, user_options = options[:binding], options[:user_options]
|
43
41
|
|
44
|
-
|
45
|
-
end # TODO: i don't want Array but Forms here - what now?
|
42
|
+
user_options = user_options.merge(wrap: binding[:wrap]) unless binding[:wrap].nil? # DISCUSS: can we leave that here?
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
44
|
+
input.send(binding.serialize_method, user_options)
|
45
|
+
end
|
50
46
|
|
47
|
+
WriteFragment = ->(input, options) { options[:binding].write(options[:doc], input, options[:as]) }
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
49
|
+
As = ->(input, options) { options[:binding].evaluate_option(:as, input, options) }
|
50
|
+
|
51
|
+
# Warning: don't rely on AssignAs/AssignName, i am not sure if i leave that as functions.
|
52
|
+
AssignAs = ->(input, options) { options[:as] = As.(input, options); input }
|
53
|
+
AssignName = ->(input, options) { options[:as] = options[:binding].name; input }
|
60
54
|
end
|