representable 1.1.7 → 1.2.0

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.
@@ -1,7 +1,9 @@
1
- h2. 1.1.7
1
+ h2. 1.2.0
2
+
3
+ * Deprecated @:except@ in favor of @:exclude@.
4
+ * A property with @false@ value will now be included in the rendered representation. Same applies to parsing, @false@ values will now be included. That particularly means properties that used to be unset (i.e. @nil@) after parsing might be @false@ now.
5
+ * You can include @nil@ values now in your representations since @#property@ respects @:represent_nil => true@.
2
6
 
3
- * Added support for coercion using virtus. Note that this presently works on class level with inline representers, only.
4
-
5
7
  h2. 1.1.6
6
8
 
7
9
  * Added @:if@ option to @property@.
@@ -247,7 +247,15 @@ You can also define conditions on properties on the class layer.
247
247
  property :friends, :if => lambda { forename == "Peter" }
248
248
  end
249
249
 
250
- When rendering or parsing, the +friends+ property is considered only if the condition block evals to true. Note that the block is executed in instance context, giving you access to instance methods.
250
+ When rendering or parsing, the +friends+ property is considered only if the condition block evals to true. Note that the block is executed in instance context, giving you access to instance methods.
251
+
252
+ === False and Nil Values
253
+
254
+ Since 1.2 +false+ values are considered when parsing and rendering. That particularly means properties that used to be unset (i.e. @nil@) after parsing might be @false@ now. Vice versa, +false+ values that weren't included in the rendered document will be visible now.
255
+
256
+ If you want +nil+ values to be included when rendering, use the +:represent_nil+ option.
257
+
258
+ property :surename, :represent_nil => true
251
259
 
252
260
  == DCI
253
261
 
@@ -1,4 +1,5 @@
1
1
  require 'representable/definition'
2
+ require 'representable/deprecations'
2
3
 
3
4
  # Representable can be used in two ways.
4
5
  #
@@ -29,6 +30,7 @@ module Representable
29
30
 
30
31
  def self.included(base)
31
32
  base.class_eval do
33
+ include Deprecations
32
34
  extend ClassMethods
33
35
  extend ClassMethods::Declarations
34
36
  extend ClassMethods::Accessors
@@ -67,14 +69,13 @@ private
67
69
 
68
70
  # Checks and returns if the property should be included.
69
71
  def skip_property?(binding, options)
70
- return true if skip_excluded_property?(binding, options) # no need for further evaluation when :except'ed
72
+ return true if skip_excluded_property?(binding, options) # no need for further evaluation when :exclude'ed
71
73
 
72
74
  skip_conditional_property?(binding)
73
75
  end
74
76
 
75
77
  def skip_excluded_property?(binding, options)
76
- return unless props = options[:except] || options[:include]
77
- props = options[:except] || options[:include]
78
+ return unless props = options[:exclude] || options[:include]
78
79
  res = props.include?(binding.definition.name.to_sym)
79
80
  options[:include] ? !res : res
80
81
  end
@@ -86,18 +87,22 @@ private
86
87
 
87
88
  # Retrieve value and write fragment to the doc.
88
89
  def compile_fragment(bin, doc)
89
- value = send(bin.definition.getter) || bin.definition.default # DISCUSS: eventually move back to Ref.
90
+ value = send(bin.definition.getter)
91
+ value = bin.definition.default_for(value)
92
+
90
93
  write_fragment_for(bin, value, doc)
91
94
  end
92
95
 
93
96
  # Parse value from doc and update the model property.
94
97
  def uncompile_fragment(bin, doc)
95
- value = read_fragment_for(bin, doc) || bin.definition.default
98
+ value = read_fragment_for(bin, doc)
99
+ value = bin.definition.default_for(value)
100
+
96
101
  send(bin.definition.setter, value)
97
102
  end
98
103
 
99
104
  def write_fragment_for(bin, value, doc) # DISCUSS: move to Binding?
100
- return unless value
105
+ return if bin.definition.skipable_nil_value?(value)
101
106
  bin.write(doc, value)
102
107
  end
103
108
 
@@ -140,6 +145,7 @@ private
140
145
  # property :name, :from => :title
141
146
  # property :name, :class => Name
142
147
  # property :name, :default => "Mike"
148
+ # property :name, :include_nil => true
143
149
  def property(name, options={})
144
150
  representable_attrs << definition_class.new(name, options)
145
151
  end
@@ -1,7 +1,7 @@
1
1
  module Representable
2
2
  class Binding
3
- attr_reader :definition
4
-
3
+ attr_reader :definition # TODO: merge Binding and Definition.
4
+
5
5
  def initialize(definition)
6
6
  @definition = definition
7
7
  end
@@ -37,9 +37,9 @@ module Representable
37
37
  (options[:from] || name).to_s
38
38
  end
39
39
 
40
- def default
41
- options[:default] ||= [] if array? # FIXME: move to CollectionBinding!
42
- options[:default]
40
+ def default_for(value)
41
+ return default if skipable_nil_value?(value)
42
+ value
43
43
  end
44
44
 
45
45
  def representer_module
@@ -49,5 +49,15 @@ module Representable
49
49
  def attribute
50
50
  options[:attribute]
51
51
  end
52
+
53
+ def skipable_nil_value?(value)
54
+ value.nil? and not options[:represent_nil]
55
+ end
56
+
57
+ private
58
+ def default
59
+ options[:default] ||= [] if array? # FIXME: move to CollectionBinding!
60
+ options[:default]
61
+ end
52
62
  end
53
63
  end
@@ -0,0 +1,9 @@
1
+ module Representable::Deprecations
2
+ def skip_excluded_property?(binding, options) # TODO: remove with 1.3.
3
+ if options[:except]
4
+ options[:exclude] = options[:except]
5
+ warn "The :except option is deprecated and will be removed in 1.3. Please use :exclude."
6
+ end # i wanted a one-liner but failed :)
7
+ super
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "1.1.7"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -55,6 +55,62 @@ class DefinitionTest < MiniTest::Spec
55
55
  end
56
56
  end
57
57
 
58
+ describe "#skipable_nil_value?" do
59
+ # default if skipable_nil_value?
60
+ before do
61
+ @def = Representable::Definition.new(:song, :represent_nil => true)
62
+ end
63
+
64
+ it "returns false when not nil" do
65
+ assert_equal false, @def.skipable_nil_value?("Disconnect, Disconnect")
66
+ end
67
+
68
+ it "returns false when nil and :represent_nil => true" do
69
+ assert_equal false, @def.skipable_nil_value?(nil)
70
+ end
71
+
72
+ it "returns true when nil and :represent_nil => false" do
73
+ assert_equal true, Representable::Definition.new(:song).skipable_nil_value?(nil)
74
+ end
75
+
76
+ it "returns false when not nil and :represent_nil => false" do
77
+ assert_equal false, Representable::Definition.new(:song).skipable_nil_value?("Fatal Flu")
78
+ end
79
+ end
80
+
81
+
82
+ describe "#default_for" do
83
+ before do
84
+ @def = Representable::Definition.new(:song, :default => "Insider")
85
+ end
86
+
87
+ it "always returns value when value not nil" do
88
+ assert_equal "Black And Blue", @def.default_for("Black And Blue")
89
+ end
90
+
91
+ it "returns false when value false" do
92
+ assert_equal false, @def.default_for(false)
93
+ end
94
+
95
+ it "returns default when value nil" do
96
+ assert_equal "Insider", @def.default_for(nil)
97
+ end
98
+
99
+ it "returns nil when value nil and :represent_nil true" do
100
+ @def = Representable::Definition.new(:song, :represent_nil => true)
101
+ assert_equal nil, @def.default_for(nil)
102
+ end
103
+
104
+ it "returns nil when value nil and :represent_nil true even when :default is set" do
105
+ @def = Representable::Definition.new(:song, :represent_nil => true, :default => "The Quest")
106
+ assert_equal nil, @def.default_for(nil)
107
+ end
108
+
109
+ it "returns nil if no :default" do
110
+ @def = Representable::Definition.new(:song)
111
+ assert_equal nil, @def.default_for(nil)
112
+ end
113
+ end
58
114
 
59
115
  describe ":collection => true" do
60
116
  before do
@@ -70,7 +126,7 @@ class DefinitionTest < MiniTest::Spec
70
126
  end
71
127
 
72
128
  it "responds to #default" do
73
- assert_equal [], @def.default
129
+ assert_equal [], @def.send(:default)
74
130
  end
75
131
  end
76
132
 
@@ -87,12 +143,12 @@ class DefinitionTest < MiniTest::Spec
87
143
  describe ":default => value" do
88
144
  it "responds to #default" do
89
145
  @def = Representable::Definition.new(:song)
90
- assert_equal nil, @def.default
146
+ assert_equal nil, @def.send(:default)
91
147
  end
92
148
 
93
149
  it "accepts a default value" do
94
150
  @def = Representable::Definition.new(:song, :default => "Atheist Peace")
95
- assert_equal "Atheist Peace", @def.default
151
+ assert_equal "Atheist Peace", @def.send(:default)
96
152
  end
97
153
  end
98
154
 
@@ -229,12 +229,16 @@ class RepresentableTest < MiniTest::Spec
229
229
  assert_equal 2, @band.groupies
230
230
  end
231
231
 
232
- it "accepts :except option" do
233
- @band.update_properties_from({"name"=>"No One's Choice", "groupies"=>2}, {:except => [:groupies]}, Representable::JSON)
232
+ it "accepts :exclude option" do
233
+ @band.update_properties_from({"name"=>"No One's Choice", "groupies"=>2}, {:exclude => [:groupies]}, Representable::JSON)
234
234
  assert_equal "No One's Choice", @band.name
235
235
  assert_equal nil, @band.groupies
236
236
  end
237
237
 
238
+ it "still accepts deprecated :except option" do # FIXME: remove :except option.
239
+ assert_equal @band.update_properties_from({"name"=>"No One's Choice", "groupies"=>2}, {:except => [:groupies]}, Representable::JSON), @band.update_properties_from({"name"=>"No One's Choice", "groupies"=>2}, {:exclude => [:groupies]}, Representable::JSON)
240
+ end
241
+
238
242
  it "accepts :include option" do
239
243
  @band.update_properties_from({"name"=>"No One's Choice", "groupies"=>2}, {:include => [:groupies]}, Representable::JSON)
240
244
  assert_equal 2, @band.groupies
@@ -245,47 +249,10 @@ class RepresentableTest < MiniTest::Spec
245
249
  assert_equal @band, @band.update_properties_from({"name"=>"Nofx"}, {}, Representable::JSON)
246
250
  end
247
251
 
248
- describe ":if" do
249
- before do
250
- @pop = Class.new(PopBand) { attr_accessor :fame }
251
- end
252
-
253
- it "respects property when condition true" do
254
- @pop.class_eval { property :fame, :if => lambda { true } }
255
- band = @pop.new
256
- band.update_properties_from({"fame"=>"oh yes"}, {}, Representable::JSON)
257
- assert_equal "oh yes", band.fame
258
- end
259
-
260
- it "ignores property when condition false" do
261
- @pop.class_eval { property :fame, :if => lambda { false } }
262
- band = @pop.new
263
- band.update_properties_from({"fame"=>"oh yes"}, {}, Representable::JSON)
264
- assert_equal nil, band.fame
265
- end
266
-
267
- it "ignores property when :except'ed even when condition is true" do
268
- @pop.class_eval { property :fame, :if => lambda { true } }
269
- band = @pop.new
270
- band.update_properties_from({"fame"=>"oh yes"}, {:except => [:fame]}, Representable::JSON)
271
- assert_equal nil, band.fame
272
- end
273
-
274
-
275
- it "executes block in instance context" do
276
- @pop.class_eval { property :fame, :if => lambda { groupies } }
277
- band = @pop.new
278
- band.groupies = true
279
- band.update_properties_from({"fame"=>"oh yes"}, {}, Representable::JSON)
280
- assert_equal "oh yes", band.fame
281
- end
282
-
283
- end
284
-
285
- it "what" do
286
-
252
+ it "includes false attributes" do
253
+ @band.update_properties_from({"groupies"=>false}, {}, Representable::JSON)
254
+ assert_equal false, @band.groupies
287
255
  end
288
-
289
256
  end
290
257
 
291
258
  describe "#create_representation_with" do
@@ -299,17 +266,79 @@ class RepresentableTest < MiniTest::Spec
299
266
  assert_equal({"name"=>"No One's Choice", "groupies"=>2}, @band.send(:create_representation_with, {}, {}, Representable::JSON))
300
267
  end
301
268
 
302
- it "accepts :except option" do
303
- hash = @band.send(:create_representation_with, {}, {:except => [:groupies]}, Representable::JSON)
269
+ it "accepts :exclude option" do
270
+ hash = @band.send(:create_representation_with, {}, {:exclude => [:groupies]}, Representable::JSON)
304
271
  assert_equal({"name"=>"No One's Choice"}, hash)
305
272
  end
306
273
 
274
+ it "still accepts deprecated :except option" do # FIXME: remove :except option.
275
+ assert_equal @band.send(:create_representation_with, {}, {:except => [:groupies]}, Representable::JSON), @band.send(:create_representation_with, {}, {:exclude => [:groupies]}, Representable::JSON)
276
+ end
277
+
307
278
  it "accepts :include option" do
308
279
  hash = @band.send(:create_representation_with, {}, {:include => [:groupies]}, Representable::JSON)
309
280
  assert_equal({"groupies"=>2}, hash)
310
281
  end
282
+
283
+ it "does not write nil attributes" do
284
+ @band.groupies = nil
285
+ assert_equal({"name"=>"No One's Choice"}, @band.send(:create_representation_with, {}, {}, Representable::JSON))
286
+ end
287
+
288
+ it "writes false attributes" do
289
+ @band.groupies = false
290
+ assert_equal({"name"=>"No One's Choice","groupies"=>false}, @band.send(:create_representation_with, {}, {}, Representable::JSON))
291
+ end
292
+
293
+ it "includes nil attribute when :represent_nil is true" do
294
+ mod = Module.new do
295
+ include Representable::JSON
296
+ property :name
297
+ property :groupies, :represent_nil => true
298
+ end
299
+
300
+ @band.extend(mod) # FIXME: use clean object.
301
+ @band.groupies = nil
302
+ hash = @band.send(:create_representation_with, {}, {}, Representable::JSON)
303
+ assert_equal({"name"=>"No One's Choice", "groupies" => nil}, hash)
304
+ end
311
305
  end
312
306
 
307
+ describe ":if" do
308
+ before do
309
+ @pop = Class.new(PopBand) { attr_accessor :fame }
310
+ end
311
+
312
+ it "respects property when condition true" do
313
+ @pop.class_eval { property :fame, :if => lambda { true } }
314
+ band = @pop.new
315
+ band.update_properties_from({"fame"=>"oh yes"}, {}, Representable::JSON)
316
+ assert_equal "oh yes", band.fame
317
+ end
318
+
319
+ it "ignores property when condition false" do
320
+ @pop.class_eval { property :fame, :if => lambda { false } }
321
+ band = @pop.new
322
+ band.update_properties_from({"fame"=>"oh yes"}, {}, Representable::JSON)
323
+ assert_equal nil, band.fame
324
+ end
325
+
326
+ it "ignores property when :exclude'ed even when condition is true" do
327
+ @pop.class_eval { property :fame, :if => lambda { true } }
328
+ band = @pop.new
329
+ band.update_properties_from({"fame"=>"oh yes"}, {:exclude => [:fame]}, Representable::JSON)
330
+ assert_equal nil, band.fame
331
+ end
332
+
333
+
334
+ it "executes block in instance context" do
335
+ @pop.class_eval { property :fame, :if => lambda { groupies } }
336
+ band = @pop.new
337
+ band.groupies = true
338
+ band.update_properties_from({"fame"=>"oh yes"}, {}, Representable::JSON)
339
+ assert_equal "oh yes", band.fame
340
+ end
341
+ end
313
342
 
314
343
  describe "Config" do
315
344
  before do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: representable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.7
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-13 00:00:00.000000000 Z
12
+ date: 2012-05-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
- requirement: &80366830 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *80366830
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: json
27
- requirement: &80366420 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *80366420
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rake
38
- requirement: &80365840 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: '0'
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *80365840
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: test_xml
49
- requirement: &80365210 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,10 +69,15 @@ dependencies:
54
69
  version: '0'
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *80365210
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: minitest
60
- requirement: &80364570 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ! '>='
@@ -65,10 +85,15 @@ dependencies:
65
85
  version: 2.8.1
66
86
  type: :development
67
87
  prerelease: false
68
- version_requirements: *80364570
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 2.8.1
69
94
  - !ruby/object:Gem::Dependency
70
95
  name: mocha
71
- requirement: &80364280 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
72
97
  none: false
73
98
  requirements:
74
99
  - - ! '>='
@@ -76,10 +101,15 @@ dependencies:
76
101
  version: '0'
77
102
  type: :development
78
103
  prerelease: false
79
- version_requirements: *80364280
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
80
110
  - !ruby/object:Gem::Dependency
81
111
  name: mongoid
82
- requirement: &80363910 !ruby/object:Gem::Requirement
112
+ requirement: !ruby/object:Gem::Requirement
83
113
  none: false
84
114
  requirements:
85
115
  - - ! '>='
@@ -87,10 +117,15 @@ dependencies:
87
117
  version: '0'
88
118
  type: :development
89
119
  prerelease: false
90
- version_requirements: *80363910
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
91
126
  - !ruby/object:Gem::Dependency
92
127
  name: virtus
93
- requirement: &80363490 !ruby/object:Gem::Requirement
128
+ requirement: !ruby/object:Gem::Requirement
94
129
  none: false
95
130
  requirements:
96
131
  - - ! '>='
@@ -98,7 +133,12 @@ dependencies:
98
133
  version: '0'
99
134
  type: :development
100
135
  prerelease: false
101
- version_requirements: *80363490
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
102
142
  description: Maps representation documents from and to Ruby objects. Includes XML
103
143
  and JSON support, plain properties, collections and compositions.
104
144
  email:
@@ -121,6 +161,7 @@ files:
121
161
  - lib/representable/bindings/xml_bindings.rb
122
162
  - lib/representable/coercion.rb
123
163
  - lib/representable/definition.rb
164
+ - lib/representable/deprecations.rb
124
165
  - lib/representable/json.rb
125
166
  - lib/representable/json/collection.rb
126
167
  - lib/representable/json/hash.rb
@@ -159,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
200
  version: '0'
160
201
  requirements: []
161
202
  rubyforge_project:
162
- rubygems_version: 1.8.10
203
+ rubygems_version: 1.8.24
163
204
  signing_key:
164
205
  specification_version: 3
165
206
  summary: Maps representation documents from and to Ruby objects. Includes XML and