representable 1.2.0 → 1.2.1

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,3 +1,8 @@
1
+ h2. 1.2.1
2
+
3
+ * Deprecated @:represent_nil@ favor of @:render_nil@.
4
+ * API change: if a property is missing in an incoming document and there is no default set it is completely ignored and *not* set in the represented object.
5
+
1
6
  h2. 1.2.0
2
7
 
3
8
  * Deprecated @:except@ in favor of @:exclude@.
@@ -251,11 +251,11 @@ When rendering or parsing, the +friends+ property is considered only if the cond
251
251
 
252
252
  === False and Nil Values
253
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.
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
255
 
256
- If you want +nil+ values to be included when rendering, use the +:represent_nil+ option.
256
+ If you want +nil+ values to be included when rendering, use the +:render_nil+ option.
257
257
 
258
- property :surename, :represent_nil => true
258
+ property :surename, :render_nil => true
259
259
 
260
260
  == DCI
261
261
 
@@ -1,5 +1,5 @@
1
- require 'representable/definition'
2
1
  require 'representable/deprecations'
2
+ require 'representable/definition'
3
3
 
4
4
  # Representable can be used in two ways.
5
5
  #
@@ -96,7 +96,11 @@ private
96
96
  # Parse value from doc and update the model property.
97
97
  def uncompile_fragment(bin, doc)
98
98
  value = read_fragment_for(bin, doc)
99
- value = bin.definition.default_for(value)
99
+
100
+ if value == Binding::FragmentNotFound
101
+ return unless bin.definition.has_default?
102
+ value = bin.definition.default
103
+ end
100
104
 
101
105
  send(bin.definition.setter, value)
102
106
  end
@@ -1,5 +1,9 @@
1
1
  module Representable
2
2
  class Binding
3
+ class FragmentNotFound
4
+ end
5
+
6
+
3
7
  attr_reader :definition # TODO: merge Binding and Definition.
4
8
 
5
9
  def initialize(definition)
@@ -27,6 +27,8 @@ module Representable
27
27
  end
28
28
 
29
29
  def read(hash)
30
+ return FragmentNotFound unless hash.has_key?(definition.from) # DISCUSS: put it all in #read for performance. not really sure if i like returning that special thing.
31
+
30
32
  fragment = hash[definition.from]
31
33
  deserialize_from(fragment)
32
34
  end
@@ -54,7 +56,6 @@ module Representable
54
56
  end
55
57
 
56
58
  def deserialize_from(fragment)
57
- fragment ||= {}
58
59
  fragment.collect { |item_fragment| deserialize(item_fragment) }
59
60
  end
60
61
  end
@@ -40,7 +40,7 @@ module Representable
40
40
 
41
41
  def read(node)
42
42
  nodes = node.search("./#{xpath}")
43
- return if nodes.size == 0 # TODO: write dedicated test!
43
+ return FragmentNotFound if nodes.size == 0 # TODO: write dedicated test!
44
44
 
45
45
  deserialize_from(nodes)
46
46
  end
@@ -7,6 +7,8 @@ module Representable
7
7
  def initialize(sym, options={})
8
8
  @name = sym.to_s
9
9
  @options = options
10
+
11
+ options[:default] ||= [] if array? # FIXME: move to CollectionBinding!
10
12
  end
11
13
 
12
14
  def clone
@@ -42,6 +44,10 @@ module Representable
42
44
  value
43
45
  end
44
46
 
47
+ def has_default?
48
+ options.has_key?(:default)
49
+ end
50
+
45
51
  def representer_module
46
52
  options[:extend]
47
53
  end
@@ -51,12 +57,10 @@ module Representable
51
57
  end
52
58
 
53
59
  def skipable_nil_value?(value)
54
- value.nil? and not options[:represent_nil]
60
+ value.nil? and not options[:render_nil]
55
61
  end
56
62
 
57
- private
58
63
  def default
59
- options[:default] ||= [] if array? # FIXME: move to CollectionBinding!
60
64
  options[:default]
61
65
  end
62
66
  end
@@ -1,9 +1,11 @@
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
1
+ module Representable
2
+ module Deprecations
3
+ def skip_excluded_property?(binding, options) # TODO: remove with 1.3.
4
+ if options[:except]
5
+ options[:exclude] = options[:except]
6
+ warn "The :except option is deprecated and will be removed in 1.3. Please use :exclude."
7
+ end # i wanted a one-liner but failed :)
8
+ super
9
+ end
8
10
  end
9
11
  end
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "1.2.0"
2
+ VERSION = "1.2.1"
3
3
  end
@@ -55,25 +55,41 @@ class DefinitionTest < MiniTest::Spec
55
55
  end
56
56
  end
57
57
 
58
+ describe "#has_default?" do
59
+ it "returns false if no :default set" do
60
+ assert_equal false, Representable::Definition.new(:song).has_default?
61
+ end
62
+
63
+ it "returns true if :default set" do
64
+ assert_equal true, Representable::Definition.new(:song, :default => nil).has_default?
65
+ end
66
+
67
+ it "returns true if :collection" do
68
+ assert_equal true, Representable::Definition.new(:songs, :collection => true).has_default?
69
+ end
70
+
71
+ end
72
+
73
+
58
74
  describe "#skipable_nil_value?" do
59
75
  # default if skipable_nil_value?
60
76
  before do
61
- @def = Representable::Definition.new(:song, :represent_nil => true)
77
+ @def = Representable::Definition.new(:song, :render_nil => true)
62
78
  end
63
79
 
64
80
  it "returns false when not nil" do
65
81
  assert_equal false, @def.skipable_nil_value?("Disconnect, Disconnect")
66
82
  end
67
83
 
68
- it "returns false when nil and :represent_nil => true" do
84
+ it "returns false when nil and :render_nil => true" do
69
85
  assert_equal false, @def.skipable_nil_value?(nil)
70
86
  end
71
87
 
72
- it "returns true when nil and :represent_nil => false" do
88
+ it "returns true when nil and :render_nil => false" do
73
89
  assert_equal true, Representable::Definition.new(:song).skipable_nil_value?(nil)
74
90
  end
75
91
 
76
- it "returns false when not nil and :represent_nil => false" do
92
+ it "returns false when not nil and :render_nil => false" do
77
93
  assert_equal false, Representable::Definition.new(:song).skipable_nil_value?("Fatal Flu")
78
94
  end
79
95
  end
@@ -96,13 +112,13 @@ class DefinitionTest < MiniTest::Spec
96
112
  assert_equal "Insider", @def.default_for(nil)
97
113
  end
98
114
 
99
- it "returns nil when value nil and :represent_nil true" do
100
- @def = Representable::Definition.new(:song, :represent_nil => true)
115
+ it "returns nil when value nil and :render_nil true" do
116
+ @def = Representable::Definition.new(:song, :render_nil => true)
101
117
  assert_equal nil, @def.default_for(nil)
102
118
  end
103
119
 
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")
120
+ it "returns nil when value nil and :render_nil true even when :default is set" do
121
+ @def = Representable::Definition.new(:song, :render_nil => true, :default => "The Quest")
106
122
  assert_equal nil, @def.default_for(nil)
107
123
  end
108
124
 
@@ -13,6 +13,23 @@ class JSONBindingTest < MiniTest::Spec
13
13
 
14
14
 
15
15
  describe "PropertyBinding" do
16
+ describe "#read" do
17
+ before do
18
+ @property = Representable::JSON::PropertyBinding.new(Representable::Definition.new(:song))
19
+ end
20
+
21
+ it "returns fragment if present" do
22
+ assert_equal "Stick The Flag Up Your Goddamn Ass, You Sonofabitch", @property.read({"song" => "Stick The Flag Up Your Goddamn Ass, You Sonofabitch"})
23
+ assert_equal "", @property.read({"song" => ""})
24
+ assert_equal nil, @property.read({"song" => nil})
25
+ end
26
+
27
+ it "returns FRAGMENT_NOT_FOUND if not in document" do
28
+ assert_equal Representable::Binding::FragmentNotFound, @property.read({})
29
+ end
30
+
31
+ end
32
+
16
33
  describe "with plain text" do
17
34
  before do
18
35
  @property = Representable::JSON::PropertyBinding.new(Representable::Definition.new(:song))
@@ -31,7 +31,7 @@ module JsonTest
31
31
 
32
32
  it "yields new object and options to block" do
33
33
  @Band.class_eval { attr_accessor :new_name }
34
- @band = @Band.from_json({}, :new_name => "Diesel Boy") do |band, options|
34
+ @band = @Band.from_json("{}", :new_name => "Diesel Boy") do |band, options|
35
35
  band.new_name= options[:new_name]
36
36
  end
37
37
  assert_equal "Diesel Boy", @band.new_name
@@ -378,8 +378,8 @@ end
378
378
  assert_equal ["Cobra Skulls", "Diesel Boy"], cd.bands.map(&:name).sort
379
379
  end
380
380
 
381
- it "creates emtpy array per default" do
382
- cd = Compilation.from_json({:compilation => {}}.to_json)
381
+ it "creates emtpy array from default if configured" do
382
+ cd = Compilation.from_json({}.to_json)
383
383
  assert_equal [], cd.bands
384
384
  end
385
385
  end
@@ -253,6 +253,26 @@ class RepresentableTest < MiniTest::Spec
253
253
  @band.update_properties_from({"groupies"=>false}, {}, Representable::JSON)
254
254
  assert_equal false, @band.groupies
255
255
  end
256
+
257
+ it "ignores (no-default) properties not present in the incoming document" do
258
+ { Representable::JSON => {},
259
+ Representable::XML => xml(%{<band/>})
260
+ }.each do |format, document|
261
+ nested_repr = Module.new do # this module is never applied.
262
+ include format
263
+ property :created_at
264
+ end
265
+
266
+ repr = Module.new do
267
+ include format
268
+ property :name, :class => Object, :extend => nested_repr
269
+ end
270
+
271
+ @band = Band.new.extend(repr)
272
+ @band.update_properties_from(document, {}, format)
273
+ assert_equal nil, @band.name, "Failed in #{format}"
274
+ end
275
+ end
256
276
  end
257
277
 
258
278
  describe "#create_representation_with" do
@@ -290,11 +310,11 @@ class RepresentableTest < MiniTest::Spec
290
310
  assert_equal({"name"=>"No One's Choice","groupies"=>false}, @band.send(:create_representation_with, {}, {}, Representable::JSON))
291
311
  end
292
312
 
293
- it "includes nil attribute when :represent_nil is true" do
313
+ it "includes nil attribute when :render_nil is true" do
294
314
  mod = Module.new do
295
315
  include Representable::JSON
296
316
  property :name
297
- property :groupies, :represent_nil => true
317
+ property :groupies, :render_nil => true
298
318
  end
299
319
 
300
320
  @band.extend(mod) # FIXME: use clean object.
@@ -4,6 +4,7 @@ Bundler.setup
4
4
  gem 'minitest'
5
5
  require 'representable'
6
6
  require 'representable/json'
7
+ require 'representable/xml'
7
8
  require 'test/unit'
8
9
  require 'minitest/spec'
9
10
  require 'minitest/autorun'
@@ -28,3 +29,13 @@ class Song
28
29
  name == other.name
29
30
  end
30
31
  end
32
+
33
+ module XmlHelper
34
+ def xml(document)
35
+ Nokogiri::XML(document).root
36
+ end
37
+ end
38
+
39
+ MiniTest::Spec.class_eval do
40
+ include XmlHelper
41
+ end
@@ -297,7 +297,7 @@ class CollectionTest < MiniTest::Spec
297
297
  assert_equal ["Cobra Skulls", "Diesel Boy"], cd.bands.map(&:name).sort
298
298
  end
299
299
 
300
- it "collections can be empty" do
300
+ it "collections can be empty when default set" do
301
301
  cd = Compilation.from_xml(%{
302
302
  <compilation>
303
303
  </compilation>
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.2.0
4
+ version: 1.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-31 00:00:00.000000000 Z
12
+ date: 2012-06-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri