representable 2.1.8 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -2
- data/CHANGES.md +31 -0
- data/lib/representable.rb +22 -13
- data/lib/representable/binding.rb +84 -68
- data/lib/representable/cached.rb +58 -0
- data/lib/representable/config.rb +3 -1
- data/lib/representable/deserializer.rb +20 -12
- data/lib/representable/hash/binding.rb +1 -0
- data/lib/representable/hash/collection.rb +2 -2
- data/lib/representable/hash_methods.rb +10 -7
- data/lib/representable/mapper.rb +32 -23
- data/lib/representable/populator.rb +1 -13
- data/lib/representable/serializer.rb +3 -1
- data/lib/representable/version.rb +1 -1
- data/representable.gemspec +3 -1
- data/test/binding_test.rb +7 -7
- data/test/cached_test.rb +135 -0
- data/test/definition_test.rb +2 -2
- data/test/hash_bindings_test.rb +4 -4
- data/test/json_test.rb +4 -4
- data/test/xml_bindings_test.rb +2 -2
- data/test/xml_test.rb +5 -5
- metadata +70 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 887d742815c848ac3b63287c8858f2988a2de41d
|
4
|
+
data.tar.gz: 78fbbf862aed5b2de60a9bc2ed7375b327a3e058
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4e93c1474e69fb743ca1072fcee054f2e075e4eaf2902b9c885ee7c86b4156db93900889820a5375d61e97a3585c14b2e70931c91722791aec7cf21606226f6
|
7
|
+
data.tar.gz: 93f25a5475e27863649981e0cb5bd553c81b5c02cfe1e16c4c630c368ec972938c4453aae7660ce0e1caf1e67e640a2ff590c5f58d17e7597e0b1abcbc0644a9
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,34 @@
|
|
1
|
+
# 2.2.0
|
2
|
+
|
3
|
+
## New Stuff
|
4
|
+
|
5
|
+
* Introduce `Representable::Cached` that will keep the mapper, which in turn will keep the bindings, which in turn will keep their representer, in case they're nested. You have to include this feature manually and you can expect a 50% and more speed-up for rendering and parsing. Not to speak about the reduced memory footprint.
|
6
|
+
|
7
|
+
``ruby
|
8
|
+
class SongDecorator < Representable::Decorator
|
9
|
+
include Representable::JSON
|
10
|
+
feature Representable::Cached
|
11
|
+
|
12
|
+
# ..
|
13
|
+
end
|
14
|
+
```
|
15
|
+
* Introduced `Decorator#update!` to re-use a decorator instance between requests. This will inject the represented object, only.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
decorator = SongDecorator.new(song)
|
19
|
+
decorator.to_json(..)
|
20
|
+
|
21
|
+
decorator.update!(louder_song)
|
22
|
+
decorator.to_json(..)
|
23
|
+
```
|
24
|
+
|
25
|
+
This is quite awesome.
|
26
|
+
|
27
|
+
## API change.
|
28
|
+
|
29
|
+
* The `:extend` option only accepts one module. `extend: [Module, Module]` does no longer work and it actually didn't work in former versions of 2.x, anyway, it just included the first element of an array.
|
30
|
+
* Remove `Binding#representer_module`.
|
31
|
+
|
1
32
|
# 2.1.8
|
2
33
|
|
3
34
|
* API change: features are now included into inline representers in the order they were specified. This used to be the other way round and is, of course, wrong, in case a sub-feature wants to override an existing method introduced by an earlier feature.
|
data/lib/representable.rb
CHANGED
@@ -8,6 +8,10 @@ require 'representable/for_collection'
|
|
8
8
|
require 'representable/represent'
|
9
9
|
require 'representable/declarative'
|
10
10
|
require 'representable/apply'
|
11
|
+
require "representable/populator"
|
12
|
+
require "representable/deserializer"
|
13
|
+
require "representable/serializer"
|
14
|
+
require "representable/cached"
|
11
15
|
|
12
16
|
|
13
17
|
require 'uber/callable'
|
@@ -32,28 +36,33 @@ module Representable
|
|
32
36
|
private
|
33
37
|
# Reads values from +doc+ and sets properties accordingly.
|
34
38
|
def update_properties_from(doc, options, format)
|
35
|
-
|
36
|
-
|
39
|
+
private_options = normalize_options!(options)
|
40
|
+
|
41
|
+
representable_mapper(format, options).deserialize(represented, doc, options, private_options)
|
37
42
|
end
|
38
43
|
|
39
44
|
# Compiles the document going through all properties.
|
40
45
|
def create_representation_with(doc, options, format)
|
41
|
-
|
46
|
+
private_options = normalize_options!(options)
|
47
|
+
|
48
|
+
representable_mapper(format, options).serialize(represented, doc, options, private_options)
|
42
49
|
end
|
43
50
|
|
44
51
|
def representable_bindings_for(format, options)
|
45
|
-
|
46
|
-
|
47
|
-
representable_attrs.collect {|attr| representable_binding_for(attr, format, options) }
|
48
|
-
# representable_attrs.binding_cache[format] ||= representable_attrs.collect {|attr| representable_binding_for(attr, format, options) }
|
52
|
+
representable_attrs.collect {|definition| representable_binding_for(definition, format, options) }
|
49
53
|
end
|
50
54
|
|
51
|
-
def representable_binding_for(
|
52
|
-
format.build(
|
55
|
+
def representable_binding_for(definition, format, options)
|
56
|
+
format.build(definition, self)
|
53
57
|
end
|
54
58
|
|
55
|
-
def
|
56
|
-
|
59
|
+
def normalize_options!(options)
|
60
|
+
# TODO: ideally, private_options would be nil if none set or so, so we could save a lot of time in nested objects.
|
61
|
+
private_options = {}
|
62
|
+
# return private_options if options.size == 0
|
63
|
+
private_options[:include] = options.delete(:include) if options[:include]
|
64
|
+
private_options[:exclude] = options.delete(:exclude) if options[:exclude]
|
65
|
+
private_options
|
57
66
|
end
|
58
67
|
|
59
68
|
def representable_attrs
|
@@ -62,11 +71,11 @@ private
|
|
62
71
|
|
63
72
|
def representable_mapper(format, options)
|
64
73
|
bindings = representable_bindings_for(format, options)
|
65
|
-
Mapper.new(bindings
|
74
|
+
Mapper.new(bindings)
|
66
75
|
end
|
67
76
|
|
68
77
|
def representation_wrap(*args)
|
69
|
-
representable_attrs.wrap_for(
|
78
|
+
representable_attrs.wrap_for(nil, represented, *args) { self.class.name }
|
70
79
|
end
|
71
80
|
|
72
81
|
def represented
|
@@ -1,7 +1,3 @@
|
|
1
|
-
require "representable/populator"
|
2
|
-
require "representable/deserializer"
|
3
|
-
require "representable/serializer"
|
4
|
-
|
5
1
|
module Representable
|
6
2
|
# The Binding wraps the Definition instance for this property and provides methods to read/write fragments.
|
7
3
|
|
@@ -19,18 +15,41 @@ module Representable
|
|
19
15
|
build_for(definition, *args)
|
20
16
|
end
|
21
17
|
|
22
|
-
def initialize(definition,
|
23
|
-
@definition
|
18
|
+
def initialize(definition, parent_decorator)
|
19
|
+
@definition = definition
|
20
|
+
@parent_decorator = parent_decorator # DISCUSS: where's this needed?
|
24
21
|
|
25
|
-
|
22
|
+
# static options. do this once.
|
23
|
+
@representable = @definition.representable?
|
24
|
+
@name = @definition.name
|
25
|
+
@skip_filters = self[:readable]==false || self[:writeable]==false || self[:if] # Does this binding contain :if, :readable or :writeable settings?
|
26
|
+
@getter = @definition.getter
|
27
|
+
@setter = @definition.setter
|
28
|
+
@array = @definition.array?
|
29
|
+
@typed = @definition.typed?
|
30
|
+
@has_default = @definition.has_default?
|
26
31
|
end
|
27
32
|
|
28
33
|
attr_reader :user_options, :represented # TODO: make private/remove.
|
29
34
|
|
35
|
+
# DISCUSS: an overall strategy to speed up option reads will come around 3.0.
|
36
|
+
attr_reader :representable, :name, :getter, :setter, :array, :typed, :skip_filters, :has_default
|
37
|
+
alias_method :representable?, :representable
|
38
|
+
alias_method :array?, :array
|
39
|
+
alias_method :typed?, :typed
|
40
|
+
alias_method :skip_filters?, :skip_filters
|
41
|
+
alias_method :has_default?, :has_default
|
42
|
+
|
30
43
|
def as # DISCUSS: private?
|
31
44
|
@as ||= evaluate_option(:as)
|
32
45
|
end
|
33
46
|
|
47
|
+
# DISCUSS:
|
48
|
+
# currently, we need to call B#update! before compile_fragment/uncompile_fragment.
|
49
|
+
# this will change to B#renderer(represented, options).call
|
50
|
+
# B#parser (represented, options).call
|
51
|
+
# goal is to have two objects for 2 entirely different tasks.
|
52
|
+
|
34
53
|
# Retrieve value and write fragment to the doc.
|
35
54
|
def compile_fragment(doc)
|
36
55
|
evaluate_option(:writer, doc) do
|
@@ -55,7 +74,6 @@ module Representable
|
|
55
74
|
end
|
56
75
|
|
57
76
|
def render_fragment(value, doc)
|
58
|
-
# DISCUSS: should we return a Skip object instead of this block trick? (same in Populator?)
|
59
77
|
fragment = serialize(value) { return } # render fragments of hash, xml, yaml.
|
60
78
|
|
61
79
|
write(doc, fragment)
|
@@ -75,7 +93,6 @@ module Representable
|
|
75
93
|
evaluate_option(:parse_filter, value, doc) { value }
|
76
94
|
end
|
77
95
|
|
78
|
-
|
79
96
|
def get
|
80
97
|
evaluate_option(:getter) do
|
81
98
|
exec_context.send(getter)
|
@@ -89,20 +106,23 @@ module Representable
|
|
89
106
|
end
|
90
107
|
|
91
108
|
# DISCUSS: do we really need that?
|
109
|
+
# 1.38 0.104 0.021 0.000 0.083 40001 Representable::Binding#representer_module_for
|
110
|
+
# 1.13 0.044 0.017 0.000 0.027 40001 Representable::Binding#representer_module_for (with memoize).
|
92
111
|
def representer_module_for(object, *args)
|
112
|
+
# TODO: cache this!
|
93
113
|
evaluate_option(:extend, object) # TODO: pass args? do we actually have args at the time this is called (compile-time)?
|
94
114
|
end
|
95
115
|
|
96
116
|
# Evaluate the option (either nil, static, a block or an instance method call) or
|
97
117
|
# executes passed block when option not defined.
|
98
118
|
def evaluate_option(name, *args)
|
99
|
-
unless proc =
|
119
|
+
unless proc = @definition[name] # TODO: this could dispatch directly to the @definition using #send?
|
100
120
|
return yield if block_given?
|
101
121
|
return
|
102
122
|
end
|
103
123
|
|
104
124
|
# TODO: it would be better if user_options was nil per default and then we just don't pass it into lambdas.
|
105
|
-
options = self[:pass_options] ? Options.new(self, user_options, represented,
|
125
|
+
options = self[:pass_options] ? Options.new(self, user_options, represented, parent_decorator) : user_options
|
106
126
|
|
107
127
|
proc.evaluate(exec_context, *(args<<options)) # from Uber::Options::Value.
|
108
128
|
end
|
@@ -110,39 +130,12 @@ module Representable
|
|
110
130
|
def [](name)
|
111
131
|
@definition[name]
|
112
132
|
end
|
113
|
-
# TODO: i don't want to define all methods here, but it is faster!
|
114
|
-
# TODO: test public interface.
|
115
|
-
def getter
|
116
|
-
@definition.getter
|
117
|
-
end
|
118
|
-
def setter
|
119
|
-
@definition.setter
|
120
|
-
end
|
121
|
-
def typed?
|
122
|
-
@definition.typed?
|
123
|
-
end
|
124
|
-
def representable?
|
125
|
-
@definition.representable?
|
126
|
-
end
|
127
|
-
def has_default?(*args)
|
128
|
-
@definition.has_default?(*args)
|
129
|
-
end
|
130
|
-
def name
|
131
|
-
@definition.name
|
132
|
-
end
|
133
|
-
def representer_module
|
134
|
-
@definition.representer_module
|
135
|
-
end
|
136
|
-
# perf : 1.7-1.9
|
137
|
-
#extend Forwardable
|
138
|
-
#def_delegators :@definition, *%w([] getter setter typed? representable? has_default? name representer_module)
|
139
|
-
# perf : 1.7-1.9
|
140
|
-
# %w([] getter setter typed? representable? has_default? name representer_module).each do |name|
|
141
|
-
# define_method(name.to_sym) { |*args| @definition.send(name, *args) }
|
142
|
-
# end
|
143
133
|
|
134
|
+
# 1.55 0.031 0.022 0.000 0.009 60004 Representable::Binding#skipable_empty_value?
|
135
|
+
# 1.51 0.030 0.022 0.000 0.008 60004 Representable::Binding#skipable_empty_value?
|
136
|
+
# after polymorphism:
|
137
|
+
# 1.44 0.031 0.022 0.000 0.009 60002 Representable::Binding#skipable_empty_value?
|
144
138
|
def skipable_empty_value?(value)
|
145
|
-
return true if array? and self[:render_empty] == false and value and value.size == 0 # TODO: change in 2.0, don't render emtpy.
|
146
139
|
value.nil? and not self[:render_nil]
|
147
140
|
end
|
148
141
|
|
@@ -151,48 +144,57 @@ module Representable
|
|
151
144
|
value
|
152
145
|
end
|
153
146
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
private
|
159
|
-
def setup!(represented, decorator, user_options)
|
160
|
-
@represented = represented
|
161
|
-
@decorator = decorator
|
162
|
-
@user_options = user_options
|
147
|
+
# Note: this method is experimental.
|
148
|
+
def update!(represented, user_options)
|
149
|
+
@represented = represented
|
150
|
+
@user_options = user_options
|
163
151
|
|
164
152
|
setup_exec_context!
|
165
153
|
end
|
166
154
|
|
167
|
-
|
168
|
-
context = represented
|
169
|
-
context = self if self[:exec_context] == :binding
|
170
|
-
context = decorator if self[:exec_context] == :decorator
|
155
|
+
attr_accessor :cached_representer
|
171
156
|
|
172
|
-
|
157
|
+
private
|
158
|
+
# 1.80 0.066 0.027 0.000 0.039 30002 Representable::Binding#setup_exec_context!
|
159
|
+
# 0.98 0.034 0.014 0.000 0.020 30002 Representable::Binding#setup_exec_context!
|
160
|
+
def setup_exec_context!
|
161
|
+
return @exec_context = @represented unless self[:exec_context]
|
162
|
+
@exec_context = self if self[:exec_context] == :binding
|
163
|
+
@exec_context = parent_decorator if self[:exec_context] == :decorator
|
173
164
|
end
|
174
165
|
|
175
|
-
attr_reader :exec_context, :
|
166
|
+
attr_reader :exec_context, :parent_decorator
|
176
167
|
|
177
168
|
def serialize(object, &block)
|
178
169
|
serializer.call(object, &block)
|
179
170
|
end
|
180
171
|
|
181
|
-
|
182
|
-
|
183
|
-
|
172
|
+
module Factories
|
173
|
+
def serializer_class
|
174
|
+
Serializer
|
175
|
+
end
|
184
176
|
|
185
|
-
|
186
|
-
|
187
|
-
|
177
|
+
def serializer
|
178
|
+
@serializer ||= serializer_class.new(self)
|
179
|
+
end
|
188
180
|
|
189
|
-
|
190
|
-
|
191
|
-
|
181
|
+
def populator
|
182
|
+
@populator ||= populator_class.new(self)
|
183
|
+
end
|
184
|
+
|
185
|
+
def populator_class
|
186
|
+
Populator
|
187
|
+
end
|
192
188
|
|
193
|
-
|
194
|
-
|
189
|
+
def deserializer_class
|
190
|
+
Deserializer
|
191
|
+
end
|
192
|
+
|
193
|
+
def deserializer
|
194
|
+
@deserializer ||= deserializer_class.new(self)
|
195
|
+
end
|
195
196
|
end
|
197
|
+
include Factories
|
196
198
|
|
197
199
|
|
198
200
|
# Options instance gets passed to lambdas when pass_options: true.
|
@@ -210,6 +212,16 @@ module Representable
|
|
210
212
|
def serializer_class
|
211
213
|
Serializer::Collection
|
212
214
|
end
|
215
|
+
|
216
|
+
def deserializer_class
|
217
|
+
Deserializer::Collection
|
218
|
+
end
|
219
|
+
|
220
|
+
def skipable_empty_value?(value)
|
221
|
+
# TODO: this can be optimized, again.
|
222
|
+
return true if value.nil? and not self[:render_nil] # FIXME: test this without the "and"
|
223
|
+
return true if self[:render_empty] == false and value and value.size == 0 # TODO: change in 2.0, don't render emtpy.
|
224
|
+
end
|
213
225
|
end
|
214
226
|
|
215
227
|
# and the same for hashes.
|
@@ -222,6 +234,10 @@ module Representable
|
|
222
234
|
def serializer_class
|
223
235
|
Serializer::Hash
|
224
236
|
end
|
237
|
+
|
238
|
+
def deserializer_class
|
239
|
+
Deserializer::Hash
|
240
|
+
end
|
225
241
|
end
|
226
242
|
end
|
227
243
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Representable
|
2
|
+
# Using this module only makes sense with Decorator representers.
|
3
|
+
module Cached
|
4
|
+
# The main point here is that the decorator instance simply saves its mapper. Since the mapper
|
5
|
+
# in turn stores the bindings, we have a straight-forward way of "caching" the bindings without
|
6
|
+
# having to mess around on the class level: this all happens in the decorator _instance_.
|
7
|
+
#
|
8
|
+
# Every binding in turn stores its nested representer (if it has one), implementing a recursive caching.
|
9
|
+
#
|
10
|
+
# Decorator -> Mapper -> [Binding->Decorator, Binding]
|
11
|
+
def representable_mapper(format, options)
|
12
|
+
@mapper ||= super.tap do |mapper|
|
13
|
+
mapper.bindings(represented, options).each { |binding| binding.extend(Binding) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# replace represented for each property in this representer.
|
18
|
+
def update!(represented)
|
19
|
+
@represented = represented
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: also for deserializer.
|
24
|
+
# TODO: create Populator in Binding, too (easier to override).
|
25
|
+
module Binding
|
26
|
+
def serializer
|
27
|
+
@__serializer ||= super.tap do |serializer|
|
28
|
+
serializer.extend(Serializer)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def deserializer
|
33
|
+
@__deserializer ||= super.tap do |deserializer|
|
34
|
+
deserializer.extend(Serializer)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Serializer
|
40
|
+
def prepare_for(mod, object)
|
41
|
+
if representer = @binding.cached_representer
|
42
|
+
return representer.update!(object)
|
43
|
+
end
|
44
|
+
|
45
|
+
# puts "--------> caching representer for #{object} in #{@binding.object_id}"
|
46
|
+
@binding.cached_representer = super(mod, object)
|
47
|
+
end
|
48
|
+
|
49
|
+
# for Deserializer::Collection.
|
50
|
+
# TODO: this is a temporary solution.
|
51
|
+
def item_deserializer
|
52
|
+
@__item_deserializer ||= super.tap do |deserializer|
|
53
|
+
deserializer.extend(Serializer)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/representable/config.rb
CHANGED
@@ -77,11 +77,13 @@ module Representable
|
|
77
77
|
end
|
78
78
|
|
79
79
|
# Computes the wrap string or returns false.
|
80
|
-
def wrap_for(name, context, *args)
|
80
|
+
def wrap_for(name, context, *args, &block)
|
81
81
|
return unless self[:wrap]
|
82
82
|
|
83
83
|
value = self[:wrap].evaluate(context, *args)
|
84
84
|
|
85
|
+
name = yield if block_given? # DISCUSS: deprecate/restructure the entire wrapping flow.
|
86
|
+
|
85
87
|
return infer_name_for(name) if value === true
|
86
88
|
value
|
87
89
|
end
|
@@ -36,21 +36,26 @@ module Representable
|
|
36
36
|
object.send(@binding.deserialize_method, fragment, options)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
prepare
|
39
|
+
module Prepare
|
40
|
+
def prepare(object)
|
41
|
+
@binding.evaluate_option(:prepare, object) do
|
42
|
+
prepare!(object)
|
43
|
+
end
|
42
44
|
end
|
43
|
-
end
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
def prepare!(object)
|
47
|
+
mod = @binding.representer_module_for(object)
|
47
48
|
|
48
|
-
|
49
|
+
return object unless mod
|
50
|
+
|
51
|
+
prepare_for(mod, object)
|
52
|
+
end
|
49
53
|
|
50
|
-
|
51
|
-
|
54
|
+
def prepare_for(mod, object)
|
55
|
+
mod.prepare(object)
|
56
|
+
end
|
52
57
|
end
|
53
|
-
|
58
|
+
include Prepare
|
54
59
|
|
55
60
|
def create_object(fragment, *args)
|
56
61
|
instance_for(fragment, *args) or class_for(fragment, *args)
|
@@ -89,8 +94,11 @@ module Representable
|
|
89
94
|
|
90
95
|
private
|
91
96
|
def deserialize!(*args)
|
92
|
-
|
93
|
-
|
97
|
+
item_deserializer.call(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
def item_deserializer
|
101
|
+
@item_deserializer = Deserializer.new(@binding)
|
94
102
|
end
|
95
103
|
end
|
96
104
|
|
@@ -4,6 +4,7 @@ module Representable
|
|
4
4
|
module Hash
|
5
5
|
class Binding < Representable::Binding
|
6
6
|
def self.build_for(definition, *args) # TODO: remove default arg.
|
7
|
+
# puts "@@@build@@ #{definition.inspect}"
|
7
8
|
return Collection.new(definition, *args) if definition.array?
|
8
9
|
return Hash.new(definition, *args) if definition.hash?
|
9
10
|
new(definition, *args)
|
@@ -19,12 +19,12 @@ module Representable::Hash
|
|
19
19
|
|
20
20
|
|
21
21
|
def create_representation_with(doc, options, format)
|
22
|
-
bin = representable_mapper(format, options).bindings.first
|
22
|
+
bin = representable_mapper(format, options).bindings(represented, options).first
|
23
23
|
bin.render_fragment(represented, doc)
|
24
24
|
end
|
25
25
|
|
26
26
|
def update_properties_from(doc, options, format)
|
27
|
-
bin = representable_mapper(format, options).bindings.first
|
27
|
+
bin = representable_mapper(format, options).bindings(represented, options).first
|
28
28
|
#value = bin.deserialize_from(doc)
|
29
29
|
value = Deserializer::Collection.new(bin).call(doc)
|
30
30
|
represented.replace(value)
|
@@ -1,14 +1,15 @@
|
|
1
1
|
module Representable
|
2
2
|
module HashMethods
|
3
3
|
def create_representation_with(doc, options, format)
|
4
|
-
|
5
|
-
|
4
|
+
hash = filter_keys_for!(represented, options) # FIXME: this modifies options and replicates logic from Representable.
|
5
|
+
bin = representable_mapper(format, options).bindings(represented, options).first
|
6
|
+
|
6
7
|
bin.render_fragment(hash, doc) # TODO: Use something along Populator, which does
|
7
8
|
end
|
8
9
|
|
9
10
|
def update_properties_from(doc, options, format)
|
10
|
-
|
11
|
-
|
11
|
+
hash = filter_keys_for!(doc, options)
|
12
|
+
bin = representable_mapper(format, options).bindings(represented, options).first
|
12
13
|
|
13
14
|
value = Deserializer::Hash.new(bin).call(hash)
|
14
15
|
# value = bin.deserialize_from(hash)
|
@@ -16,9 +17,11 @@ module Representable
|
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
19
|
-
def filter_keys_for(hash, options)
|
20
|
-
|
21
|
-
|
20
|
+
def filter_keys_for!(hash, options)
|
21
|
+
excluding = options[:exclude]
|
22
|
+
# TODO: use same filtering method as in normal representer in Representable#create_representation_with.
|
23
|
+
return hash unless props = options.delete(:exclude) || options.delete(:include)
|
24
|
+
hash.reject { |k,v| excluding ? props.include?(k.to_sym) : !props.include?(k.to_sym) }
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
data/lib/representable/mapper.rb
CHANGED
@@ -3,50 +3,59 @@ module Representable
|
|
3
3
|
# Conditionals are handled here, too.
|
4
4
|
class Mapper
|
5
5
|
module Methods
|
6
|
-
def initialize(bindings
|
7
|
-
@
|
8
|
-
@bindings = bindings
|
6
|
+
def initialize(bindings)
|
7
|
+
@bindings = bindings
|
9
8
|
end
|
10
9
|
|
11
|
-
|
10
|
+
def bindings(represented, options)
|
11
|
+
@bindings.each do |binding|
|
12
|
+
binding.update!(represented, options)
|
13
|
+
end
|
14
|
+
end
|
12
15
|
|
13
|
-
def deserialize(doc, options)
|
14
|
-
bindings.each do |bin|
|
15
|
-
deserialize_property(bin, doc, options)
|
16
|
+
def deserialize(represented, doc, options, private_options)
|
17
|
+
bindings(represented, options).each do |bin|
|
18
|
+
deserialize_property(bin, doc, options, private_options)
|
16
19
|
end
|
17
|
-
|
20
|
+
represented
|
18
21
|
end
|
19
22
|
|
20
|
-
def serialize(doc, options)
|
21
|
-
bindings.each do |bin|
|
22
|
-
serialize_property(bin, doc, options)
|
23
|
+
def serialize(represented, doc, options, private_options)
|
24
|
+
bindings(represented, options).each do |bin|
|
25
|
+
serialize_property(bin, doc, options, private_options)
|
23
26
|
end
|
24
27
|
doc
|
25
28
|
end
|
26
29
|
|
27
30
|
private
|
28
|
-
def serialize_property(binding, doc, options)
|
29
|
-
return if skip_property?(binding,
|
31
|
+
def serialize_property(binding, doc, options, private_options)
|
32
|
+
return if skip_property?(binding, private_options.merge(:action => :serialize))
|
30
33
|
compile_fragment(binding, doc)
|
31
34
|
end
|
32
35
|
|
33
|
-
def deserialize_property(binding, doc, options)
|
34
|
-
return if skip_property?(binding,
|
36
|
+
def deserialize_property(binding, doc, options, private_options)
|
37
|
+
return if skip_property?(binding, private_options.merge(:action => :deserialize))
|
35
38
|
uncompile_fragment(binding, doc)
|
36
39
|
end
|
37
40
|
|
38
41
|
# Checks and returns if the property should be included.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
# 1.78 0.107 0.025 0.000 0.081 30002 Representable::Mapper::Methods#skip_property?
|
43
|
+
# 0.96 0.013 0.013 0.000 0.000 30002 Representable::Mapper::Methods#skip_property? hash only
|
44
|
+
# 1.15 0.025 0.016 0.000 0.009 30002 Representable::Mapper::Methods#skip_property?
|
45
|
+
|
46
|
+
def skip_property?(binding, private_options)
|
47
|
+
return unless private_options[:include] || private_options[:exclude] || binding.skip_filters?
|
48
|
+
|
49
|
+
return true if skip_excluded_property?(binding, private_options) # no need for further evaluation when :exclude'ed
|
50
|
+
return true if skip_protected_property(binding, private_options)
|
42
51
|
|
43
52
|
skip_conditional_property?(binding)
|
44
53
|
end
|
45
54
|
|
46
|
-
def skip_excluded_property?(binding,
|
47
|
-
return unless props =
|
55
|
+
def skip_excluded_property?(binding, private_options)
|
56
|
+
return unless props = private_options[:exclude] || private_options[:include]
|
48
57
|
res = props.include?(binding.name.to_sym)
|
49
|
-
|
58
|
+
private_options[:include] ? !res : res
|
50
59
|
end
|
51
60
|
|
52
61
|
def skip_conditional_property?(binding)
|
@@ -56,8 +65,8 @@ module Representable
|
|
56
65
|
end
|
57
66
|
|
58
67
|
# DISCUSS: this could be just another :if option in a Pipeline?
|
59
|
-
def skip_protected_property(binding,
|
60
|
-
|
68
|
+
def skip_protected_property(binding, private_options)
|
69
|
+
private_options[:action] == :serialize ? binding[:readable] == false : binding[:writeable] == false
|
61
70
|
end
|
62
71
|
|
63
72
|
def compile_fragment(bin, doc)
|
@@ -35,12 +35,8 @@ module Representable
|
|
35
35
|
deserializer.call(fragment) # CollectionDeserializer/HashDeserializer/etc.
|
36
36
|
end
|
37
37
|
|
38
|
-
def deserializer_class
|
39
|
-
Deserializer
|
40
|
-
end
|
41
|
-
|
42
38
|
def deserializer
|
43
|
-
|
39
|
+
@binding.deserializer
|
44
40
|
end
|
45
41
|
|
46
42
|
|
@@ -52,17 +48,9 @@ module Representable
|
|
52
48
|
def deserialize(fragment)
|
53
49
|
return deserializer.call(fragment)
|
54
50
|
end
|
55
|
-
|
56
|
-
def deserializer
|
57
|
-
Deserializer::Collection.new(@binding)
|
58
|
-
end
|
59
51
|
end
|
60
52
|
|
61
53
|
class Hash < self
|
62
|
-
private
|
63
|
-
def deserializer_class
|
64
|
-
Deserializer::Hash
|
65
|
-
end
|
66
54
|
end
|
67
55
|
end
|
68
56
|
end
|
@@ -27,8 +27,10 @@ module Representable
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
# 0.33 0.004 0.004 0.000 0.000 20001 Hash#merge!
|
31
|
+
# 0.00 0.000 0.000 0.000 0.000 1 Hash#merge!
|
30
32
|
def marshal(object, user_options)
|
31
|
-
object.send(@binding.serialize_method, user_options
|
33
|
+
object.send(@binding.serialize_method, user_options)
|
32
34
|
end
|
33
35
|
|
34
36
|
|
data/representable.gemspec
CHANGED
@@ -30,5 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.add_development_dependency "mocha", ">= 0.13.0"
|
31
31
|
s.add_development_dependency "mongoid"
|
32
32
|
s.add_development_dependency "virtus"
|
33
|
-
s.add_development_dependency "json", '
|
33
|
+
s.add_development_dependency "json", '>= 1.7.7'
|
34
|
+
|
35
|
+
s.add_development_dependency "ruby-prof"
|
34
36
|
end
|
data/test/binding_test.rb
CHANGED
@@ -5,7 +5,7 @@ class BindingTest < MiniTest::Spec
|
|
5
5
|
let (:render_nil_definition) { Representable::Definition.new(:song, :render_nil => true) }
|
6
6
|
|
7
7
|
describe "#skipable_empty_value?" do
|
8
|
-
let (:binding) { Binding.new(render_nil_definition, nil
|
8
|
+
let (:binding) { Binding.new(render_nil_definition, nil) }
|
9
9
|
|
10
10
|
# don't skip when present.
|
11
11
|
it { binding.skipable_empty_value?("Disconnect, Disconnect").must_equal false }
|
@@ -14,16 +14,16 @@ class BindingTest < MiniTest::Spec
|
|
14
14
|
it { binding.skipable_empty_value?(nil).must_equal false }
|
15
15
|
|
16
16
|
# skip when nil and :render_nil undefined.
|
17
|
-
it { Binding.new(Representable::Definition.new(:song), nil
|
17
|
+
it { Binding.new(Representable::Definition.new(:song), nil).skipable_empty_value?(nil).must_equal true }
|
18
18
|
|
19
19
|
# don't skip when nil and :render_nil undefined.
|
20
|
-
it { Binding.new(Representable::Definition.new(:song), nil
|
20
|
+
it { Binding.new(Representable::Definition.new(:song), nil).skipable_empty_value?("Fatal Flu").must_equal false }
|
21
21
|
end
|
22
22
|
|
23
23
|
|
24
24
|
describe "#default_for" do
|
25
25
|
let (:definition) { Representable::Definition.new(:song, :default => "Insider") }
|
26
|
-
let (:binding) { Binding.new(definition, nil
|
26
|
+
let (:binding) { Binding.new(definition, nil) }
|
27
27
|
|
28
28
|
# return value when value present.
|
29
29
|
it { binding.default_for("Black And Blue").must_equal "Black And Blue" }
|
@@ -35,12 +35,12 @@ class BindingTest < MiniTest::Spec
|
|
35
35
|
it { binding.default_for(nil).must_equal "Insider" }
|
36
36
|
|
37
37
|
# return nil when value nil and render_nil: true.
|
38
|
-
it { Binding.new(render_nil_definition, nil
|
38
|
+
it { Binding.new(render_nil_definition, nil).default_for(nil).must_equal nil }
|
39
39
|
|
40
40
|
# return nil when value nil and render_nil: true, even when :default is set" do
|
41
|
-
it { Binding.new(Representable::Definition.new(:song, :render_nil => true, :default => "The Quest"), nil
|
41
|
+
it { Binding.new(Representable::Definition.new(:song, :render_nil => true, :default => "The Quest"), nil).default_for(nil).must_equal nil }
|
42
42
|
|
43
43
|
# return nil if no :default
|
44
|
-
it { Binding.new(Representable::Definition.new(:song), nil
|
44
|
+
it { Binding.new(Representable::Definition.new(:song), nil).default_for(nil).must_equal nil }
|
45
45
|
end
|
46
46
|
end
|
data/test/cached_test.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require 'ruby-prof'
|
3
|
+
|
4
|
+
class CachedTest < MiniTest::Spec
|
5
|
+
# TODO: also test with feature(Cached)
|
6
|
+
|
7
|
+
module Model
|
8
|
+
Song = Struct.new(:title, :composer)
|
9
|
+
Album = Struct.new(:name, :songs, :artist)
|
10
|
+
Artist = Struct.new(:name, :hidden_taste)
|
11
|
+
end
|
12
|
+
|
13
|
+
class SongRepresenter < Representable::Decorator
|
14
|
+
include Representable::Hash
|
15
|
+
feature Representable::Cached
|
16
|
+
|
17
|
+
property :title, render_filter: lambda { |value, doc, options| "#{value}:#{options.user_options}" }, pass_options: true
|
18
|
+
property :composer, class: Model::Artist do
|
19
|
+
property :name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class AlbumRepresenter < Representable::Decorator
|
24
|
+
include Representable::Hash
|
25
|
+
include Representable::Cached
|
26
|
+
|
27
|
+
property :name
|
28
|
+
collection :songs, decorator: SongRepresenter, class: Model::Song
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe "serialization" do
|
33
|
+
let (:album_hash) { {"name"=>"Louder And Even More Dangerous", "songs"=>[{"title"=>"Southbound:{:volume=>10}"}, {"title"=>"Jailbreak:{:volume=>10}"}]} }
|
34
|
+
|
35
|
+
let (:song) { Model::Song.new("Jailbreak") }
|
36
|
+
let (:song2) { Model::Song.new("Southbound") }
|
37
|
+
let (:album) { Model::Album.new("Live And Dangerous", [song, song2, Model::Song.new("Emerald")]) }
|
38
|
+
let (:representer) { AlbumRepresenter.new(album) }
|
39
|
+
|
40
|
+
it do
|
41
|
+
album2 = Model::Album.new("Louder And Even More Dangerous", [song2, song])
|
42
|
+
|
43
|
+
# makes sure options are passed correctly.
|
44
|
+
representer.to_hash(volume: 9).must_equal({"name"=>"Live And Dangerous",
|
45
|
+
"songs"=>[{"title"=>"Jailbreak:{:volume=>9}"}, {"title"=>"Southbound:{:volume=>9}"}, {"title"=>"Emerald:{:volume=>9}"}]}) # called in Deserializer/Serializer
|
46
|
+
|
47
|
+
# representer becomes reusable as it is stateless.
|
48
|
+
representer.update!(album2)
|
49
|
+
|
50
|
+
# makes sure options are passed correctly.
|
51
|
+
representer.to_hash(volume:10).must_equal(album_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
# profiling
|
55
|
+
it "xx" do
|
56
|
+
RubyProf.start
|
57
|
+
representer.to_hash
|
58
|
+
res = RubyProf.stop
|
59
|
+
|
60
|
+
printer = RubyProf::FlatPrinter.new(res)
|
61
|
+
|
62
|
+
data = StringIO.new
|
63
|
+
printer.print(data)
|
64
|
+
data = data.string
|
65
|
+
|
66
|
+
printer.print(STDOUT)
|
67
|
+
|
68
|
+
# only 1 nested decorators are instantiated, Song.
|
69
|
+
data.must_match "1 <Class::Representable::Decorator>#prepare"
|
70
|
+
# a total of 4 properties in the object graph.
|
71
|
+
data.must_match "4 Representable::Binding#initialize"
|
72
|
+
# 2 mappers for Album, Song
|
73
|
+
data.must_match "2 Representable::Mapper::Methods#initialize"
|
74
|
+
# 6 deserializers as the songs collection uses 2.
|
75
|
+
data.must_match "3 Representable::Deserializer#initialize"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
describe "deserialization" do
|
81
|
+
let (:album_hash) {
|
82
|
+
{
|
83
|
+
"name"=>"Louder And Even More Dangerous",
|
84
|
+
"songs"=>[
|
85
|
+
{"title"=>"Southbound", "composer"=>{"name"=>"Lynott"}},
|
86
|
+
{"title"=>"Jailbreak", "composer"=>{"name"=>"Phil Lynott"}},
|
87
|
+
{"title"=>"Emerald"}
|
88
|
+
]
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
it do
|
93
|
+
album = Model::Album.new
|
94
|
+
|
95
|
+
AlbumRepresenter.new(album).from_hash(album_hash)
|
96
|
+
|
97
|
+
album.songs.size.must_equal 3
|
98
|
+
album.name.must_equal "Louder And Even More Dangerous"
|
99
|
+
album.songs[0].title.must_equal "Southbound"
|
100
|
+
album.songs[0].composer.name.must_equal "Lynott"
|
101
|
+
album.songs[1].title.must_equal "Jailbreak"
|
102
|
+
album.songs[1].composer.name.must_equal "Phil Lynott"
|
103
|
+
album.songs[2].title.must_equal "Emerald"
|
104
|
+
album.songs[2].composer.must_equal nil
|
105
|
+
|
106
|
+
# TODO: test options.
|
107
|
+
end
|
108
|
+
|
109
|
+
it do
|
110
|
+
representer = AlbumRepresenter.new(Model::Album.new)
|
111
|
+
|
112
|
+
RubyProf.start
|
113
|
+
representer.from_hash(album_hash)
|
114
|
+
res = RubyProf.stop
|
115
|
+
|
116
|
+
printer = RubyProf::FlatPrinter.new(res)
|
117
|
+
|
118
|
+
data = StringIO.new
|
119
|
+
printer.print(data)
|
120
|
+
data = data.string
|
121
|
+
|
122
|
+
# only 2 nested decorators are instantiated, Song, and Artist.
|
123
|
+
data.must_match "2 <Class::Representable::Decorator>#prepare"
|
124
|
+
# a total of 5 properties in the object graph.
|
125
|
+
data.must_match "5 Representable::Binding#initialize"
|
126
|
+
# three mappers for Album, Song, composer
|
127
|
+
data.must_match "3 Representable::Mapper::Methods#initialize"
|
128
|
+
# 6 deserializers as the songs collection uses 2.
|
129
|
+
data.must_match "6 Representable::Deserializer#initialize"
|
130
|
+
# one populater for every property.
|
131
|
+
data.must_match "5 Representable::Populator#initialize"
|
132
|
+
# printer.print(STDOUT)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/test/definition_test.rb
CHANGED
@@ -214,8 +214,8 @@ class DefinitionTest < MiniTest::Spec
|
|
214
214
|
describe "#create_binding" do
|
215
215
|
it "executes the block (without special context)" do
|
216
216
|
definition = Representable::Definition.new(:title, :binding => lambda { |*args| @binding = Representable::Binding.new(*args) })
|
217
|
-
definition.create_binding(object=Object.new
|
218
|
-
@binding.instance_variable_get(:@
|
217
|
+
definition.create_binding(object=Object.new).must_equal @binding
|
218
|
+
@binding.instance_variable_get(:@parent_decorator).must_equal object
|
219
219
|
end
|
220
220
|
end
|
221
221
|
|
data/test/hash_bindings_test.rb
CHANGED
@@ -15,7 +15,7 @@ class HashBindingTest < MiniTest::Spec
|
|
15
15
|
describe "PropertyBinding" do
|
16
16
|
describe "#read" do
|
17
17
|
before do
|
18
|
-
@property = Representable::Hash::Binding.new(Representable::Definition.new(:song), nil
|
18
|
+
@property = Representable::Hash::Binding.new(Representable::Definition.new(:song), nil)
|
19
19
|
end
|
20
20
|
|
21
21
|
it "returns fragment if present" do
|
@@ -35,7 +35,7 @@ class HashBindingTest < MiniTest::Spec
|
|
35
35
|
describe "CollectionBinding" do
|
36
36
|
describe "with plain text items" do
|
37
37
|
before do
|
38
|
-
@property = Representable::Hash::Binding::Collection.new(Representable::Definition.new(:songs, :collection => true), Album.new
|
38
|
+
@property = Representable::Hash::Binding::Collection.new(Representable::Definition.new(:songs, :collection => true), Album.new)
|
39
39
|
end
|
40
40
|
|
41
41
|
it "extracts with #read" do
|
@@ -56,7 +56,7 @@ class HashBindingTest < MiniTest::Spec
|
|
56
56
|
describe "HashBinding" do
|
57
57
|
describe "with plain text items" do
|
58
58
|
before do
|
59
|
-
@property = Representable::Hash::Binding::Hash.new(Representable::Definition.new(:songs, :hash => true), nil
|
59
|
+
@property = Representable::Hash::Binding::Hash.new(Representable::Definition.new(:songs, :hash => true), nil)
|
60
60
|
end
|
61
61
|
|
62
62
|
it "extracts with #read" do
|
@@ -72,7 +72,7 @@ class HashBindingTest < MiniTest::Spec
|
|
72
72
|
|
73
73
|
describe "with objects" do
|
74
74
|
before do
|
75
|
-
@property = Representable::Hash::Binding::Hash.new(Representable::Definition.new(:songs, :hash => true, :class => Song, :extend => SongRepresenter), nil
|
75
|
+
@property = Representable::Hash::Binding::Hash.new(Representable::Definition.new(:songs, :hash => true, :class => Song, :extend => SongRepresenter), nil)
|
76
76
|
end
|
77
77
|
|
78
78
|
it "doesn't change the represented hash in #write" do
|
data/test/json_test.rb
CHANGED
@@ -88,15 +88,15 @@ module JsonTest
|
|
88
88
|
|
89
89
|
describe "#build_for" do
|
90
90
|
it "returns TextBinding" do
|
91
|
-
assert_kind_of Representable::Hash::Binding, Representable::Hash::Binding.build_for(Def.new(:band), nil
|
91
|
+
assert_kind_of Representable::Hash::Binding, Representable::Hash::Binding.build_for(Def.new(:band), nil)
|
92
92
|
end
|
93
93
|
|
94
94
|
it "returns HashBinding" do
|
95
|
-
assert_kind_of Representable::Hash::Binding::Hash, Representable::Hash::Binding.build_for(Def.new(:band, :hash => true), nil
|
95
|
+
assert_kind_of Representable::Hash::Binding::Hash, Representable::Hash::Binding.build_for(Def.new(:band, :hash => true), nil)
|
96
96
|
end
|
97
97
|
|
98
98
|
it "returns CollectionBinding" do
|
99
|
-
assert_kind_of Representable::Hash::Binding::Collection, Representable::Hash::Binding.build_for(Def.new(:band, :collection => true), nil
|
99
|
+
assert_kind_of Representable::Hash::Binding::Collection, Representable::Hash::Binding.build_for(Def.new(:band, :collection => true), nil)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -119,7 +119,7 @@ module JsonTest
|
|
119
119
|
module AlbumRepresenter
|
120
120
|
include Representable::JSON
|
121
121
|
property :best_song, :class => Song, :extend => SongRepresenter
|
122
|
-
collection :songs, :class => Song, :extend =>
|
122
|
+
collection :songs, :class => Song, :extend => SongRepresenter
|
123
123
|
end
|
124
124
|
|
125
125
|
|
data/test/xml_bindings_test.rb
CHANGED
@@ -29,7 +29,7 @@ class XMLBindingTest < MiniTest::Spec
|
|
29
29
|
describe "AttributeBinding" do
|
30
30
|
describe "with plain text items" do
|
31
31
|
before do
|
32
|
-
@property = Representable::XML::Binding::Attribute.new(Representable::Definition.new(:name, :attribute => true), nil
|
32
|
+
@property = Representable::XML::Binding::Attribute.new(Representable::Definition.new(:name, :attribute => true), nil)
|
33
33
|
end
|
34
34
|
|
35
35
|
it "extracts with #read" do
|
@@ -46,7 +46,7 @@ class XMLBindingTest < MiniTest::Spec
|
|
46
46
|
|
47
47
|
describe "ContentBinding" do
|
48
48
|
before do
|
49
|
-
@property = Representable::XML::Binding::Content.new(Representable::Definition.new(:name, :content => true), nil
|
49
|
+
@property = Representable::XML::Binding::Content.new(Representable::Definition.new(:name, :content => true), nil)
|
50
50
|
end
|
51
51
|
|
52
52
|
it "extracts with #read" do
|
data/test/xml_test.rb
CHANGED
@@ -104,20 +104,20 @@ class XmlTest < MiniTest::Spec
|
|
104
104
|
|
105
105
|
describe "XML::Binding#build_for" do
|
106
106
|
it "returns AttributeBinding" do
|
107
|
-
assert_kind_of XML::Binding::Attribute, XML::Binding.build_for(Def.new(:band, :as => "band", :attribute => true), nil
|
107
|
+
assert_kind_of XML::Binding::Attribute, XML::Binding.build_for(Def.new(:band, :as => "band", :attribute => true), nil)
|
108
108
|
end
|
109
109
|
|
110
110
|
it "returns Binding" do
|
111
|
-
assert_kind_of XML::Binding, XML::Binding.build_for(Def.new(:band, :class => Hash), nil
|
112
|
-
assert_kind_of XML::Binding, XML::Binding.build_for(Def.new(:band, :as => :content), nil
|
111
|
+
assert_kind_of XML::Binding, XML::Binding.build_for(Def.new(:band, :class => Hash), nil)
|
112
|
+
assert_kind_of XML::Binding, XML::Binding.build_for(Def.new(:band, :as => :content), nil)
|
113
113
|
end
|
114
114
|
|
115
115
|
it "returns CollectionBinding" do
|
116
|
-
assert_kind_of XML::Binding::Collection, XML::Binding.build_for(Def.new(:band, :collection => :true), nil
|
116
|
+
assert_kind_of XML::Binding::Collection, XML::Binding.build_for(Def.new(:band, :collection => :true), nil)
|
117
117
|
end
|
118
118
|
|
119
119
|
it "returns HashBinding" do
|
120
|
-
assert_kind_of XML::Binding::Hash, XML::Binding.build_for(Def.new(:band, :hash => :true), nil
|
120
|
+
assert_kind_of XML::Binding::Hash, XML::Binding.build_for(Def.new(:band, :hash => :true), nil)
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: representable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -140,16 +140,30 @@ dependencies:
|
|
140
140
|
name: json
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - "
|
143
|
+
- - ">="
|
144
144
|
- !ruby/object:Gem::Version
|
145
145
|
version: 1.7.7
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- - "
|
150
|
+
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 1.7.7
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: ruby-prof
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
153
167
|
description: Renders and parses JSON/XML/YAML documents from and to Ruby objects.
|
154
168
|
Includes plain properties, collections, nesting, coercion and more.
|
155
169
|
email:
|
@@ -171,6 +185,7 @@ files:
|
|
171
185
|
- lib/representable/apply.rb
|
172
186
|
- lib/representable/autoload.rb
|
173
187
|
- lib/representable/binding.rb
|
188
|
+
- lib/representable/cached.rb
|
174
189
|
- lib/representable/coercion.rb
|
175
190
|
- lib/representable/config.rb
|
176
191
|
- lib/representable/debug.rb
|
@@ -207,6 +222,7 @@ files:
|
|
207
222
|
- test/as_test.rb
|
208
223
|
- test/benchmarking.rb
|
209
224
|
- test/binding_test.rb
|
225
|
+
- test/cached_test.rb
|
210
226
|
- test/class_test.rb
|
211
227
|
- test/coercion_test.rb
|
212
228
|
- test/config/inherit_test.rb
|
@@ -277,4 +293,53 @@ signing_key:
|
|
277
293
|
specification_version: 4
|
278
294
|
summary: Renders and parses JSON/XML/YAML documents from and to Ruby objects. Includes
|
279
295
|
plain properties, collections, nesting, coercion and more.
|
280
|
-
test_files:
|
296
|
+
test_files:
|
297
|
+
- test/as_test.rb
|
298
|
+
- test/benchmarking.rb
|
299
|
+
- test/binding_test.rb
|
300
|
+
- test/cached_test.rb
|
301
|
+
- test/class_test.rb
|
302
|
+
- test/coercion_test.rb
|
303
|
+
- test/config/inherit_test.rb
|
304
|
+
- test/config_test.rb
|
305
|
+
- test/decorator_scope_test.rb
|
306
|
+
- test/decorator_test.rb
|
307
|
+
- test/definition_test.rb
|
308
|
+
- test/example.rb
|
309
|
+
- test/examples/object.rb
|
310
|
+
- test/exec_context_test.rb
|
311
|
+
- test/features_test.rb
|
312
|
+
- test/filter_test.rb
|
313
|
+
- test/for_collection_test.rb
|
314
|
+
- test/generic_test.rb
|
315
|
+
- test/getter_setter_test.rb
|
316
|
+
- test/hash_bindings_test.rb
|
317
|
+
- test/hash_test.rb
|
318
|
+
- test/if_test.rb
|
319
|
+
- test/inherit_test.rb
|
320
|
+
- test/inheritable_test.rb
|
321
|
+
- test/inline_test.rb
|
322
|
+
- test/instance_test.rb
|
323
|
+
- test/is_representable_test.rb
|
324
|
+
- test/json_test.rb
|
325
|
+
- test/lonely_test.rb
|
326
|
+
- test/mongoid_test.rb
|
327
|
+
- test/nested_test.rb
|
328
|
+
- test/object_test.rb
|
329
|
+
- test/parse_strategy_test.rb
|
330
|
+
- test/pass_options_test.rb
|
331
|
+
- test/prepare_test.rb
|
332
|
+
- test/reader_writer_test.rb
|
333
|
+
- test/realistic_benchmark.rb
|
334
|
+
- test/represent_test.rb
|
335
|
+
- test/representable_test.rb
|
336
|
+
- test/schema_test.rb
|
337
|
+
- test/serialize_deserialize_test.rb
|
338
|
+
- test/skip_test.rb
|
339
|
+
- test/stringify_hash_test.rb
|
340
|
+
- test/test_helper.rb
|
341
|
+
- test/test_helper_test.rb
|
342
|
+
- test/wrap_test.rb
|
343
|
+
- test/xml_bindings_test.rb
|
344
|
+
- test/xml_test.rb
|
345
|
+
- test/yaml_test.rb
|