representable 0.10.2 → 0.10.3

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,6 +1,11 @@
1
+ h2. 0.10.3
2
+
3
+ * Added @representable_property :default => ...@ option which is considered for both serialization and deserialization. The default is applied when the value is @nil@. Note that an empty string ain't @nil@.
4
+ * @representable_attrs@ are now pushed to instance level as soon as possible.
5
+
1
6
  h2. 0.10.2
2
7
 
3
- * Added `representable_property :accessors => false` option to suppress adding accessors.
8
+ * Added @representable_property :accessors => false@ option to suppress adding accessors.
4
9
  * @Representable.representation_wrap@ is no longer inherited.
5
10
  * Representers can now be defined in modules. They inherit to including modules.
6
11
 
@@ -37,7 +37,7 @@ Since you keep forgetting the heroes of your childhood you decide to implement a
37
37
 
38
38
  This declares two simple properties. Representable will automatically add accessors to the class.
39
39
 
40
- If you don't want declarations in your models, use a module.
40
+ Alternatively, if you don't want declarations in your models, use a module.
41
41
 
42
42
  module HeroRepresentation
43
43
  include Representable
@@ -14,10 +14,10 @@ module Representable
14
14
 
15
15
  # Reads values from +doc+ and sets properties accordingly.
16
16
  def update_properties_from(doc, &block)
17
- self.class.representable_bindings.each do |bin|
17
+ representable_bindings.each do |bin|
18
18
  next if eval_property_block(bin, &block) # skip if block is false.
19
19
 
20
- value = bin.read(doc)
20
+ value = bin.read(doc) || bin.definition.default
21
21
  send(bin.definition.setter, value)
22
22
  end
23
23
  self
@@ -26,10 +26,10 @@ module Representable
26
26
  private
27
27
  # Compiles the document going through all properties.
28
28
  def create_representation_with(doc, &block)
29
- self.class.representable_bindings.each do |bin|
29
+ representable_bindings.each do |bin|
30
30
  next if eval_property_block(bin, &block) # skip if block is false.
31
31
 
32
- value = send(bin.definition.getter) # DISCUSS: eventually move back to Ref.
32
+ value = send(bin.definition.getter) || bin.definition.default # DISCUSS: eventually move back to Ref.
33
33
  bin.write(doc, value) if value
34
34
  end
35
35
  doc
@@ -42,6 +42,14 @@ private
42
42
  block_given? and not yield binding.definition.name.to_sym
43
43
  end
44
44
 
45
+ def representable_attrs
46
+ @representable_attrs ||= self.class.representable_attrs # DISCUSS: copy, or better not?
47
+ end
48
+
49
+ def representable_bindings
50
+ representable_attrs.map {|attr| binding_for_definition(attr) }
51
+ end
52
+
45
53
 
46
54
  module ClassMethods # :nodoc:
47
55
  module Declarations
@@ -62,6 +70,7 @@ private
62
70
  # representable_property :name, :from => :title
63
71
  # representable_property :name, :as => Name
64
72
  # representable_property :name, :accessors => false
73
+ # representable_property :name, :default => "Mike"
65
74
  def representable_property(name, options={})
66
75
  attr = add_representable_property(name, options)
67
76
 
@@ -8,14 +8,10 @@ module Representable
8
8
  end
9
9
 
10
10
  def read(hash)
11
- value_from_hash(hash) or default
11
+ value_from_hash(hash)
12
12
  end
13
13
 
14
14
  private
15
- def default
16
- ""
17
- end
18
-
19
15
  def collect_for(hash)
20
16
  nodes = hash[definition.from] or return
21
17
  nodes = [nodes] unless nodes.is_a?(Array)
@@ -51,16 +47,11 @@ module Representable
51
47
  end
52
48
 
53
49
  private
54
- def default
55
- []
56
- end
57
-
58
50
  def value_from_hash(hash)
59
51
  collect_for(hash) do |node|
60
52
  definition.sought_type.from_hash(node) # call #from_hash as it's already deserialized.
61
53
  end
62
54
  end
63
-
64
55
  end
65
56
  end
66
57
  end
@@ -8,14 +8,10 @@ module Representable
8
8
  end
9
9
 
10
10
  def read(xml)
11
- value_from_node(xml) or default
11
+ value_from_node(xml)
12
12
  end
13
13
 
14
14
  private
15
- def default
16
- ""
17
- end
18
-
19
15
  def xpath
20
16
  definition.from
21
17
  end
@@ -80,10 +76,6 @@ module Representable
80
76
  end
81
77
 
82
78
  private
83
- def default
84
- []
85
- end
86
-
87
79
  # Deserializes the ref's element from +xml+.
88
80
  def value_from_node(xml)
89
81
  collect_for(xml) do |node|
@@ -1,7 +1,7 @@
1
1
  module Representable
2
2
  # Created at class compile time. Keeps configuration options for one property.
3
3
  class Definition
4
- attr_reader :name, :sought_type, :from
4
+ attr_reader :name, :sought_type, :from, :default
5
5
  alias_method :getter, :name
6
6
 
7
7
  def initialize(sym, options={})
@@ -9,6 +9,8 @@ module Representable
9
9
  @array = options[:collection]
10
10
  @from = (options[:from] || name).to_s
11
11
  @sought_type = options[:as] || :text
12
+ @default = options[:default]
13
+ @default ||= [] if array?
12
14
 
13
15
  # FIXME: move me to xml.
14
16
  if options[:from].to_s =~ /^@/
@@ -14,17 +14,13 @@ module Representable
14
14
 
15
15
  def self.included(base)
16
16
  base.class_eval do
17
- include Representable
17
+ include Representable # either in Hero or HeroRepresentation.
18
18
  extend ClassMethods
19
19
  end
20
20
  end
21
21
 
22
22
 
23
23
  module ClassMethods
24
- def binding_for_definition(definition)
25
- (BINDING_FOR_TYPE[definition.sought_type] or ObjectBinding).new(definition)
26
- end
27
-
28
24
  # Creates a new object from the passed JSON document.
29
25
  def from_json(*args, &block)
30
26
  new.from_json(*args, &block)
@@ -61,5 +57,9 @@ module Representable
61
57
  def to_json(*args, &block)
62
58
  to_hash(*args, &block).to_json
63
59
  end
60
+
61
+ def binding_for_definition(definition)
62
+ (BINDING_FOR_TYPE[definition.sought_type] or ObjectBinding).new(definition)
63
+ end
64
64
  end
65
65
  end
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "0.10.2"
2
+ VERSION = "0.10.3"
3
3
  end
@@ -19,10 +19,6 @@ module Representable
19
19
 
20
20
 
21
21
  module ClassMethods
22
- def binding_for_definition(definition)
23
- (BINDING_FOR_TYPE[definition.sought_type] or ObjectBinding).new(definition)
24
- end
25
-
26
22
  # Creates a new Ruby object from XML using mapping information declared in the class.
27
23
  #
28
24
  # Accepts a block yielding the currently iterated Definition. If the block returns false
@@ -59,5 +55,9 @@ module Representable
59
55
  def to_xml(*args, &block)
60
56
  to_node(*args, &block).to_s
61
57
  end
58
+
59
+ def binding_for_definition(definition)
60
+ (BINDING_FOR_TYPE[definition.sought_type] or ObjectBinding).new(definition)
61
+ end
62
62
  end
63
63
  end
@@ -1,17 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class BindingsTest < MiniTest::Spec
4
- describe "ObjectRef with []" do
5
- before do
6
- @ref = Representable::XML::ObjectBinding.new(Representable::Definition.new(:songs, :as => [Hash]))
7
- end
8
-
9
- it "responds to #default" do
10
- assert_equal [], @ref.send(:default)
11
- end
12
- end
13
-
14
-
15
4
  describe "TextRef#read" do
16
5
  def parse_xml(xml); Nokogiri::XML(xml).root; end
17
6
 
@@ -62,6 +62,10 @@ class DefinitionTest < MiniTest::Spec
62
62
  it "responds to #sought_type" do
63
63
  assert_equal :text, @def.sought_type
64
64
  end
65
+
66
+ it "responds to #default" do
67
+ assert_equal [], @def.default
68
+ end
65
69
  end
66
70
 
67
71
  describe ":as => Item" do
@@ -73,4 +77,16 @@ class DefinitionTest < MiniTest::Spec
73
77
  assert_equal Hash, @def.sought_type
74
78
  end
75
79
  end
80
+
81
+ describe ":default => value" do
82
+ it "responds to #default" do
83
+ @def = Representable::Definition.new(:song)
84
+ assert_equal nil, @def.default
85
+ end
86
+
87
+ it "accepts a default value" do
88
+ @def = Representable::Definition.new(:song, :default => "Atheist Peace")
89
+ assert_equal "Atheist Peace", @def.default
90
+ end
91
+ end
76
92
  end
@@ -17,6 +17,8 @@ module JsonTest
17
17
  self.name = name if name
18
18
  end
19
19
  end
20
+
21
+ @band = @Band.new
20
22
  end
21
23
 
22
24
 
@@ -136,18 +138,18 @@ module JsonTest
136
138
 
137
139
  describe "#binding_for_definition" do
138
140
  it "returns ObjectBinding" do
139
- assert_kind_of Json::ObjectBinding, @Band.binding_for_definition(Def.new(:band, :as => Hash))
141
+ assert_kind_of Json::ObjectBinding, @band.binding_for_definition(Def.new(:band, :as => Hash))
140
142
  end
141
143
 
142
144
  it "returns TextBinding" do
143
- assert_kind_of Json::TextBinding, @Band.binding_for_definition(Def.new(:band))
145
+ assert_kind_of Json::TextBinding, @band.binding_for_definition(Def.new(:band))
144
146
  end
145
147
  end
146
148
 
147
149
  describe "#representable_bindings" do
148
150
  it "returns bindings for each property" do
149
- assert_equal 2, @Band.representable_bindings.size
150
- assert_equal "name", @Band.representable_bindings.first.definition.name
151
+ assert_equal 2, @band.send(:representable_bindings).size
152
+ assert_equal "name", @band.send(:representable_bindings).first.definition.name
151
153
  end
152
154
  end
153
155
  end
@@ -229,7 +231,51 @@ module JsonTest
229
231
  assert_equal '{"songName":"Run To The Hills"}', song.to_json
230
232
  end
231
233
  end
234
+
235
+ describe ":default => :value" do
236
+ before do
237
+ @Album = Class.new do
238
+ include Representable::JSON
239
+ representable_property :name, :default => "30 Years Live"
240
+ end
241
+ end
242
+
243
+ describe "#from_json" do
244
+ it "uses default when property nil in doc" do
245
+ album = @Album.from_json({}.to_json)
246
+ assert_equal "30 Years Live", album.name
247
+ end
248
+
249
+ it "uses value from doc when present" do
250
+ album = @Album.from_json({:name => "Live At The Wireless"}.to_json)
251
+ assert_equal "Live At The Wireless", album.name
252
+ end
253
+
254
+ it "uses value from doc when empty string" do
255
+ album = @Album.from_json({:name => ""}.to_json)
256
+ assert_equal "", album.name
257
+ end
258
+ end
259
+
260
+ describe "#to_json" do
261
+ it "uses default when not available in object" do
262
+ assert_equal "{\"name\":\"30 Years Live\"}", @Album.new.to_json
263
+ end
264
+
265
+ it "uses value from represented object when present" do
266
+ album = @Album.new
267
+ album.name = "Live At The Wireless"
268
+ assert_equal "{\"name\":\"Live At The Wireless\"}", album.to_json
269
+ end
270
+
271
+ it "uses value from represented object when emtpy string" do
272
+ album = @Album.new
273
+ album.name = ""
274
+ assert_equal "{\"name\":\"\"}", album.to_json
275
+ end
276
+ end
232
277
  end
278
+ end
233
279
 
234
280
 
235
281
  class CollectionTest < MiniTest::Spec
@@ -275,7 +321,7 @@ module JsonTest
275
321
  assert_equal ["Cobra Skulls", "Diesel Boy"], cd.bands.map(&:name).sort
276
322
  end
277
323
 
278
- it "collections can be empty" do
324
+ it "creates emtpy array per default" do
279
325
  cd = Compilation.from_json({:compilation => {}}.to_json)
280
326
  assert_equal [], cd.bands
281
327
  end
@@ -64,6 +64,18 @@ class RepresentableTest < MiniTest::Spec
64
64
  assert_equal "{\"name\":\"Vention Dention\",\"street_cred\":1}", vd.to_json
65
65
  end
66
66
 
67
+ #it "allows including the concrete representer module only" do
68
+ # require 'representable/json'
69
+ # module RockBandRepresentation
70
+ # include Representable::JSON
71
+ # representable_property :name
72
+ # end
73
+ # vd = class VH
74
+ # include RockBandRepresentation
75
+ # end.new
76
+ # vd.name = "Van Halen"
77
+ # assert_equal "{\"name\":\"Van Halen\"}", vd.to_json
78
+ #end
67
79
  end
68
80
  end
69
81
 
@@ -32,6 +32,8 @@ class XmlTest < MiniTest::Spec
32
32
  representable_property :name
33
33
  representable_property :label
34
34
  end
35
+
36
+ @band = @Band.new
35
37
  end
36
38
 
37
39
 
@@ -138,15 +140,15 @@ class XmlTest < MiniTest::Spec
138
140
 
139
141
  describe "#binding_for_definition" do
140
142
  it "returns AttributeBinding" do
141
- assert_kind_of XML::AttributeBinding, @Band.binding_for_definition(Def.new(:band, :from => "@band"))
143
+ assert_kind_of XML::AttributeBinding, @band.binding_for_definition(Def.new(:band, :from => "@band"))
142
144
  end
143
145
 
144
146
  it "returns ObjectBinding" do
145
- assert_kind_of XML::ObjectBinding, @Band.binding_for_definition(Def.new(:band, :as => Hash))
147
+ assert_kind_of XML::ObjectBinding, @band.binding_for_definition(Def.new(:band, :as => Hash))
146
148
  end
147
149
 
148
150
  it "returns TextBinding" do
149
- assert_kind_of XML::TextBinding, @Band.binding_for_definition(Def.new(:band, :from => :content))
151
+ assert_kind_of XML::TextBinding, @band.binding_for_definition(Def.new(:band, :from => :content))
150
152
  end
151
153
  end
152
154
  end
metadata CHANGED
@@ -1,90 +1,111 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: representable
3
- version: !ruby/object:Gem::Version
4
- version: 0.10.2
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 10
8
+ - 3
9
+ version: 0.10.3
6
10
  platform: ruby
7
- authors:
11
+ authors:
8
12
  - Nick Sutterer
9
13
  autorequire:
10
14
  bindir: bin
11
15
  cert_chain: []
12
- date: 2011-12-03 00:00:00.000000000Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
16
+
17
+ date: 2011-12-07 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: nokogiri
16
- requirement: &75503660 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
22
31
  type: :runtime
23
- prerelease: false
24
- version_requirements: *75503660
25
- - !ruby/object:Gem::Dependency
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
26
34
  name: json
27
- requirement: &75503430 !ruby/object:Gem::Requirement
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
28
37
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0'
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
33
44
  type: :runtime
34
- prerelease: false
35
- version_requirements: *75503430
36
- - !ruby/object:Gem::Dependency
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
37
47
  name: rake
38
- requirement: &75503180 !ruby/object:Gem::Requirement
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
39
50
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
43
- version: '0'
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
44
57
  type: :development
45
- prerelease: false
46
- version_requirements: *75503180
47
- - !ruby/object:Gem::Dependency
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
48
60
  name: test_xml
49
- requirement: &75502870 !ruby/object:Gem::Requirement
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
50
63
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
55
70
  type: :development
56
- prerelease: false
57
- version_requirements: *75502870
58
- - !ruby/object:Gem::Dependency
71
+ version_requirements: *id004
72
+ - !ruby/object:Gem::Dependency
59
73
  name: minitest
60
- requirement: &75502410 !ruby/object:Gem::Requirement
74
+ prerelease: false
75
+ requirement: &id005 !ruby/object:Gem::Requirement
61
76
  none: false
62
- requirements:
77
+ requirements:
63
78
  - - ~>
64
- - !ruby/object:Gem::Version
65
- version: '2.8'
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 2
82
+ - 8
83
+ version: "2.8"
66
84
  type: :development
67
- prerelease: false
68
- version_requirements: *75502410
69
- - !ruby/object:Gem::Dependency
85
+ version_requirements: *id005
86
+ - !ruby/object:Gem::Dependency
70
87
  name: mocha
71
- requirement: &75501950 !ruby/object:Gem::Requirement
88
+ prerelease: false
89
+ requirement: &id006 !ruby/object:Gem::Requirement
72
90
  none: false
73
- requirements:
74
- - - ! '>='
75
- - !ruby/object:Gem::Version
76
- version: '0'
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
77
97
  type: :development
78
- prerelease: false
79
- version_requirements: *75501950
80
- description: Maps representation documents from and to Ruby objects. Includes XML
81
- and JSON support, plain properties, collections and compositions.
82
- email:
98
+ version_requirements: *id006
99
+ description: Maps representation documents from and to Ruby objects. Includes XML and JSON support, plain properties, collections and compositions.
100
+ email:
83
101
  - apotonick@gmail.com
84
102
  executables: []
103
+
85
104
  extensions: []
105
+
86
106
  extra_rdoc_files: []
87
- files:
107
+
108
+ files:
88
109
  - .gitignore
89
110
  - .gitmodules
90
111
  - .rspec
@@ -108,29 +129,37 @@ files:
108
129
  - test/representable_test.rb
109
130
  - test/test_helper.rb
110
131
  - test/xml_test.rb
132
+ has_rdoc: true
111
133
  homepage: http://representable.apotomo.de
112
134
  licenses: []
135
+
113
136
  post_install_message:
114
137
  rdoc_options: []
115
- require_paths:
138
+
139
+ require_paths:
116
140
  - lib
117
- required_ruby_version: !ruby/object:Gem::Requirement
141
+ required_ruby_version: !ruby/object:Gem::Requirement
118
142
  none: false
119
- requirements:
120
- - - ! '>='
121
- - !ruby/object:Gem::Version
122
- version: '0'
123
- required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ segments:
147
+ - 0
148
+ version: "0"
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
150
  none: false
125
- requirements:
126
- - - ! '>='
127
- - !ruby/object:Gem::Version
128
- version: '0'
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ segments:
155
+ - 0
156
+ version: "0"
129
157
  requirements: []
158
+
130
159
  rubyforge_project:
131
- rubygems_version: 1.8.10
160
+ rubygems_version: 1.3.7
132
161
  signing_key:
133
162
  specification_version: 3
134
- summary: Maps representation documents from and to Ruby objects. Includes XML and
135
- JSON support, plain properties, collections and compositions.
163
+ summary: Maps representation documents from and to Ruby objects. Includes XML and JSON support, plain properties, collections and compositions.
136
164
  test_files: []
165
+