representable 2.1.1 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
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