representable 2.1.1 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d4c1cc5843478c8c3c889dabd023eca71e622da8
4
- data.tar.gz: c8b2850a2418de5d94dbc1024f5d84c93a979976
3
+ metadata.gz: 00d2530b55af3101dbb2526089519f0bdb549b83
4
+ data.tar.gz: ed33d0ffceab14486efa0a0e61edc84e3de03de7
5
5
  SHA512:
6
- metadata.gz: 8447a73176a4dfd5cc11d7767721e083757e2c9eeeb9e0bde32d73b17fea141fd6954ca05ce45f9e88c8393d9341981cce7b4e5fc4836f7eaed39d05a0890bc8
7
- data.tar.gz: a4175164b4f3eb64db40630b7d9fcc4e1574cc075268f87e6cdafbe2a8648861a07f0302fbbc54431ac6bb5934b4c3f12e704a3459a4b3c134acf029ff794496
6
+ metadata.gz: 4fb790c37b9c9bd1abe2f6caeff855031b5a263c44f58e8b43f37f1ada791a2e1a87efdf6dabd26a95c1e184e3d88a5049296c0459b0b95c1ac42bdd96937e72
7
+ data.tar.gz: 597b5614752170094138b69d7c02ef70deb5a23c300d35e22bfa3f9232b5d8572ac53dd84dd1e7500f35940f3263cd96687a981878e046f3b29a94fba3cef22a
data/CHANGES.md CHANGED
@@ -1,8 +1,16 @@
1
+ # 2.1.3
2
+
3
+ * Like 2.1.2 (got yanked) because I thought it's buggy but it's not. What has changed is that `Serializer::Collection#serialize` no longer does `collection.collect` but `collection.each` since this allows filtering out unwanted elements.
4
+
5
+ # 2.1.2
6
+
7
+ * Added `:skip_render` options.
8
+
1
9
  # 2.1.1
2
10
 
3
11
  * Added `Definition#delete!` to remove options.
4
12
  * Added `Representable::apply` do iterate and change schemas.
5
- * Added `Config.remove` to remove properties.
13
+ * Added `Config#remove` to remove properties.
6
14
  * Added `Representable::Debug` which just has to be included into your represented object.
7
15
 
8
16
  ```ruby
data/README.md CHANGED
@@ -62,6 +62,8 @@ song = Song.new.extend(SongRepresenter).from_json(%{ {"title":"Roxanne"} })
62
62
  #=> #<Song title="Roxanne", track=nil>
63
63
  ```
64
64
 
65
+ Note that parsing hashes per default does [require string keys](#symbol-keys-vs-string-keys) and does _not_ pick up symbol keys.
66
+
65
67
  ## Extend vs. Decorator
66
68
 
67
69
  If you don't want representer modules to be mixed into your objects (using `#extend`) you can use the `Decorator` strategy [described below](#decorator-vs-extend). Decorating instead of extending was introduced in 1.4.
@@ -528,6 +530,7 @@ Here's a list of all dynamic options and their argument signature.
528
530
  * `reader: lambda { |document, args| }` ([see Read And Write](#overriding-read-and-write))
529
531
  * `writer: lambda { |document, args| }` ([see Read And Write](#overriding-read-and-write))
530
532
  * `skip_parse: lambda { |fragment, args| }` ([see Skip Parsing](#skip-parsing))
533
+ * `skip_render: lambda { |object, args| }` ([see Skip Rendering](#skip-rendering))
531
534
  * `parse_filter: lambda { |fragment, document, args| }` ([see Filters](#filters)))
532
535
  * `render_filter: lambda { |value, document, args| }` ([see Filters](#filters))
533
536
  * `if: lambda { |args| }` ([see Conditions](#conditions))
@@ -590,6 +593,17 @@ end
590
593
 
591
594
  This won't parse empty incoming songs in the collection.
592
595
 
596
+ ## Skip Rendering
597
+
598
+ The exact same also works for rendering. You can skip rendering properties and items of collections.
599
+
600
+ ```ruby
601
+ property :title, skip_render: lambda { |object, options| options[:skip_title] == true }
602
+ ```
603
+
604
+ In collections, this will be run per item.
605
+
606
+
593
607
  ## Callable Options
594
608
 
595
609
  While lambdas are one option for dynamic options, you might also pass a "callable" object to a directive.
@@ -1300,12 +1314,57 @@ end
1300
1314
 
1301
1315
  This is an implementation detail most people shouldn't worry about.
1302
1316
 
1317
+ ## Symbol Keys vs. String Keys
1318
+
1319
+ When parsing representable reads properties from hashes by using their string keys.
1320
+
1321
+ ```ruby
1322
+ song.from_hash("title" => "Road To Never")
1323
+ ```
1324
+
1325
+ To allow symbol keys also include the `AllowSymbols` module.
1326
+
1327
+ ```ruby
1328
+ module SongRepresenter
1329
+ include Representable::Hash
1330
+ include Representable::Hash::AllowSymbols
1331
+ # ..
1332
+ end
1333
+ ```
1334
+
1335
+ This will give you a behavior close to Rails' `HashWithIndifferentAccess` by stringifying the incoming hash internally.
1336
+
1337
+
1338
+ ## Debugging
1339
+
1340
+ Representable is a generic mapper using recursions and things that might be hard to understand from the outside. That's why we got the `Debug` module which will give helpful output about what it's doing when parsing or rendering.
1341
+
1342
+ You can extend objects on the run to see what they're doing.
1343
+
1344
+ ```ruby
1345
+ song.extend(SongRepresenter).extend(Representable::Debug).from_json("..")
1346
+ song.extend(SongRepresenter).extend(Representable::Debug).to_json
1347
+ ```
1348
+
1349
+ `Debug` can also be included statically into your representer or decorator.
1350
+
1351
+ ```ruby
1352
+ class SongRepresenter < Representable::Decorator
1353
+ include Representable::JSON
1354
+ include Representable::Debug
1355
+
1356
+ property :title
1357
+ end
1358
+ ```
1359
+
1360
+ It's probably a good idea not to do this in production.
1361
+
1303
1362
 
1304
1363
  ## Copyright
1305
1364
 
1306
1365
  Representable started as a heavily simplified fork of the ROXML gem. Big thanks to Ben Woosley for his inspiring work.
1307
1366
 
1308
- * Copyright (c) 2011-2013 Nick Sutterer <apotonick@gmail.com>
1367
+ * Copyright (c) 2011-2015 Nick Sutterer <apotonick@gmail.com>
1309
1368
  * ROXML is Copyright (c) 2004-2009 Ben Woosley, Zak Mandhro and Anders Engstrom.
1310
1369
 
1311
1370
  Representable is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -55,7 +55,8 @@ module Representable
55
55
  end
56
56
 
57
57
  def render_fragment(value, doc)
58
- fragment = serialize(value) # render fragments of hash, xml, yaml.
58
+ # DISCUSS: should we return a Skip object instead of this block trick? (same in Populator?)
59
+ fragment = serialize(value) { return } # render fragments of hash, xml, yaml.
59
60
 
60
61
  write(doc, fragment)
61
62
  end
@@ -173,8 +174,8 @@ module Representable
173
174
 
174
175
  attr_reader :exec_context, :decorator
175
176
 
176
- def serialize(object)
177
- serializer.call(object)
177
+ def serialize(object, &block)
178
+ serializer.call(object, &block)
178
179
  end
179
180
 
180
181
  def serializer_class
@@ -111,7 +111,7 @@ module Representable
111
111
  end
112
112
 
113
113
  def dynamic_options
114
- [:as, :getter, :setter, :class, :instance, :reader, :writer, :extend, :prepare, :if, :deserialize, :serialize, :render_filter, :parse_filter, :skip_parse]
114
+ [:as, :getter, :setter, :class, :instance, :reader, :writer, :extend, :prepare, :if, :deserialize, :serialize, :render_filter, :parse_filter, :skip_parse, :skip_render]
115
115
  end
116
116
 
117
117
  def handle_extend!(options)
@@ -17,6 +17,7 @@ module Representable
17
17
  return unless @binding.has_default?
18
18
  value = @binding[:default]
19
19
  else
20
+ # DISCUSS: should we return a Skip object instead of this block trick? (same in Binding#serialize?)
20
21
  value = deserialize(fragment) { return } # stop here if skip_parse?
21
22
  end
22
23
 
@@ -1,16 +1,23 @@
1
1
  require "representable/deserializer"
2
2
 
3
3
  module Representable
4
+ # serialize -> serialize! -> marshal. # TODO: same flow in deserialize.
4
5
  class Serializer < Deserializer
5
- def call(object)
6
+ def call(object, &block)
6
7
  return object if object.nil? # DISCUSS: move to Object#serialize ?
7
8
 
8
- serialize(object, @binding.user_options)
9
+ serialize(object, @binding.user_options, &block)
9
10
  end
10
11
 
11
12
  private
13
+ def serialize(object, user_options, &block)
14
+ return yield if @binding.evaluate_option(:skip_render, object) # this will jump out of #render_fragment. introduce Skip object here.
15
+
16
+ serialize!(object, user_options)
17
+ end
18
+
12
19
  # Serialize one object by calling to_json etc. on it.
13
- def serialize(object, user_options)
20
+ def serialize!(object, user_options)
14
21
  object = prepare(object)
15
22
 
16
23
  return object unless @binding.representable?
@@ -27,7 +34,15 @@ module Representable
27
34
 
28
35
  class Collection < self
29
36
  def serialize(array, *args)
30
- array.collect { |item| super(item, *args) } # TODO: i don't want Array but Forms here - what now?
37
+ collection = [] # TODO: unify with Deserializer::Collection.
38
+
39
+ array.each do |item|
40
+ next if @binding.evaluate_option(:skip_render, item) # TODO: allow skipping entire collections? same for deserialize.
41
+
42
+ collection << serialize!(item, *args)
43
+ end # TODO: i don't want Array but Forms here - what now?
44
+
45
+ collection
31
46
  end
32
47
  end
33
48
 
@@ -1,3 +1,3 @@
1
1
  module Representable
2
- VERSION = "2.1.1"
2
+ VERSION = "2.1.3"
3
3
  end
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
  s.add_dependency "uber", "~> 0.0.7"
25
25
 
26
26
  s.add_development_dependency "rake"
27
- s.add_development_dependency "test_xml", ">= 0.1.6"
27
+ s.add_development_dependency "test_xml", "0.1.6"
28
28
  s.add_development_dependency "minitest", ">= 5.4.1"
29
29
  s.add_development_dependency "mocha", ">= 0.13.0"
30
30
  s.add_development_dependency "mongoid"
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class SkipTest < MiniTest::Spec
3
+ class SkipParseTest < MiniTest::Spec
4
4
  representer! do
5
5
  property :title
6
6
  property :band,
@@ -25,4 +25,42 @@ class SkipTest < MiniTest::Spec
25
25
  # skip_parse is _per item_.
26
26
  let (:airplay) { OpenStruct.new(station: "JJJ") }
27
27
  it { song.from_hash({"airplays" => [{"station" => "JJJ"}, {}]}, skip?: true).airplays.must_equal [airplay] }
28
+
29
+ # it skips parsing of items as if they hadn't been in the document.
30
+ it { song.from_hash({"airplays" => [{"station" => "JJJ"}, {}, {"station" => "JJJ"}]}, skip?: true).airplays.must_equal [airplay, airplay] }
31
+ end
32
+
33
+ class SkipRenderTest < MiniTest::Spec
34
+ representer! do
35
+ property :title
36
+ property :band,
37
+ skip_render: lambda { |object, opts| opts[:skip?] and object.name == "Rancid" } do
38
+ property :name
39
+ end
40
+
41
+ collection :airplays,
42
+ skip_render: lambda { |object, opts| puts object.inspect; opts[:skip?] and object.station == "Radio Dreyeckland" } do
43
+ property :station
44
+ end
45
+ end
46
+
47
+ let (:song) { OpenStruct.new(title: "Black Night", band: OpenStruct.new(name: "Time Again")).extend(representer) }
48
+ let (:skip_song) { OpenStruct.new(title: "Time Bomb", band: OpenStruct.new(name: "Rancid")).extend(representer) }
49
+
50
+ # do render.
51
+ it { song.to_hash(skip?: true).must_equal({"title"=>"Black Night", "band"=>{"name"=>"Time Again"}}) }
52
+ # skip.
53
+ it { skip_song.to_hash(skip?: true).must_equal({"title"=>"Time Bomb"}) }
54
+
55
+ # do render all collection items.
56
+ it do
57
+ song = OpenStruct.new(airplays: [OpenStruct.new(station: "JJJ"), OpenStruct.new(station: "ABC")]).extend(representer)
58
+ song.to_hash(skip?: true).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
59
+ end
60
+
61
+ # skip middle item.
62
+ it do
63
+ song = OpenStruct.new(airplays: [OpenStruct.new(station: "JJJ"), OpenStruct.new(station: "Radio Dreyeckland"), OpenStruct.new(station: "ABC")]).extend(representer)
64
+ song.to_hash(skip?: true).must_equal({"airplays"=>[{"station"=>"JJJ"}, {"station"=>"ABC"}]})
65
+ end
28
66
  end
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.1.1
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-22 00:00:00.000000000 Z
11
+ date: 2014-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -70,14 +70,14 @@ dependencies:
70
70
  name: test_xml
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - '='
74
74
  - !ruby/object:Gem::Version
75
75
  version: 0.1.6
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - '='
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.1.6
83
83
  - !ruby/object:Gem::Dependency