representable 3.0.3 → 3.0.4
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 +4 -4
- data/.travis.yml +3 -1
- data/CHANGES.md +5 -0
- data/README.md +1 -1
- data/TODO +1 -3
- data/TODO-4.0.md +72 -0
- data/lib/representable/declarative.rb +3 -3
- data/lib/representable/deserializer.rb +1 -1
- data/lib/representable/serializer.rb +1 -1
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml.rb +6 -4
- data/lib/representable/xml/binding.rb +19 -12
- data/lib/representable/xml/namespace.rb +122 -0
- data/representable.gemspec +2 -2
- data/test/as_test.rb +2 -2
- data/test/binding_test.rb +7 -7
- data/test/cached_test.rb +13 -13
- data/test/class_test.rb +2 -2
- data/test/coercion_test.rb +1 -1
- data/test/config_test.rb +5 -5
- data/test/decorator_scope_test.rb +1 -1
- data/test/decorator_test.rb +8 -8
- data/test/default_test.rb +1 -1
- data/test/defaults_options_test.rb +3 -3
- data/test/definition_test.rb +9 -11
- data/test/examples/object.rb +1 -5
- data/test/exec_context_test.rb +2 -2
- data/test/features_test.rb +3 -3
- data/test/filter_test.rb +2 -2
- data/test/for_collection_test.rb +8 -8
- data/test/generic_test.rb +11 -11
- data/test/hash_bindings_test.rb +1 -1
- data/test/hash_test.rb +13 -13
- data/test/heritage_test.rb +16 -13
- data/test/if_test.rb +3 -3
- data/test/include_exclude_test.rb +2 -2
- data/test/inherit_test.rb +3 -3
- data/test/inline_test.rb +13 -13
- data/test/instance_test.rb +2 -2
- data/test/json_test.rb +4 -6
- data/test/lonely_test.rb +15 -15
- data/test/nested_test.rb +6 -6
- data/test/object_test.rb +4 -4
- data/test/parse_pipeline_test.rb +0 -2
- data/test/pipeline_test.rb +7 -7
- data/test/populator_test.rb +7 -7
- data/test/prepare_test.rb +2 -2
- data/test/represent_test.rb +10 -10
- data/test/representable_test.rb +7 -7
- data/test/schema_test.rb +3 -6
- data/test/skip_test.rb +6 -6
- data/test/test_helper.rb +16 -6
- data/test/wrap_test.rb +8 -8
- data/test/xml_namespace_test.rb +186 -0
- data/test/xml_test.rb +53 -34
- data/test/yaml_test.rb +11 -11
- metadata +9 -7
- data/lib/representable/TODO.getting_serious +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04ca3309b8af78dd1eaa8b4d47c457323180a881
|
4
|
+
data.tar.gz: c7d43dc372fc53576a6b64f22d3fc0bd1bff5a4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 528696ff8d8eae7b409566d9831a0117a90a361fdabe5a0345d0e5accac5cfbb2f3bfae5a34589000b5bdbf2632f7951356861215d210172c602b581694e68dc
|
7
|
+
data.tar.gz: 4d7409a62a9a25d31fc1c67d20e2b32b9cd0a1d8e9987b2cbe118bd4e069fe271dd82127f3e7656b92f01e8f1266524965def4089e439b4a1eac370e13a06bff
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# 3.0.4
|
2
|
+
|
3
|
+
* Add proper XML namespace support.
|
4
|
+
* [internal] Replace `XML::Binding#node_for` with function `XML::Node`.
|
5
|
+
|
1
6
|
# 3.0.3
|
2
7
|
|
3
8
|
* Replace `Uber::Option` with the new [`Declarative::Option`](https://github.com/apotonick/declarative-option). This should result in a significant performance boost.
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Representable maps Ruby objects to documents and back.
|
|
5
5
|
[](https://gitter.im/trailblazer/chat)
|
6
6
|
[](http://trailblazer.to/newsletter/)
|
7
7
|
[](https://travis-ci.org/trailblazer/representable)
|
9
9
|
[](http://badge.fury.io/rb/representable)
|
10
10
|
|
11
11
|
In other words: Take an object and decorate it with a representer module. This will allow you to render a JSON, XML or YAML document from that object. But that's only half of it! You can also use representers to parse a document and create or populate an object.
|
data/TODO
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
* Pass key/index as first block arg to :class and :extend
|
2
2
|
class: |key, hsh|
|
3
3
|
|
4
|
-
* Allow passing options to Binding#serialize.
|
5
|
-
serialize(.., options{:exclude => ..})
|
6
4
|
|
7
5
|
document `XML::AttributeHash` etc
|
8
6
|
|
@@ -37,4 +35,4 @@ module ReaderWriter
|
|
37
35
|
* DISCUSS: should inline representers be created at runtime, so we don't need ::representer_engine?
|
38
36
|
* deprecate `Decorator::Coercion`.
|
39
37
|
|
40
|
-
* cleanup XML so it matches the current #serialize standard.
|
38
|
+
* cleanup XML so it matches the current #serialize standard.
|
data/TODO-4.0.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Decorator
|
2
|
+
|
3
|
+
XML::Binding::Collection.to_xml(represented)
|
4
|
+
bindings.each bin.to_xml
|
5
|
+
|
6
|
+
|
7
|
+
# hat vorteil: [].each{ Collection.to_xml(item) }
|
8
|
+
|
9
|
+
* make all properties "Object-like", even arrays of strings etc. This saves us from having `extend ObjectBinding if typed?` and we could just call to_hash/from_hash on all attributes. performance issues here? otherwise: implement!
|
10
|
+
|
11
|
+
|
12
|
+
# how to?
|
13
|
+
|
14
|
+
class CH
|
15
|
+
wrap :character
|
16
|
+
prpoerty :a
|
17
|
+
|
18
|
+
|
19
|
+
class
|
20
|
+
proerty :author, dec: CH
|
21
|
+
|
22
|
+
# how to?
|
23
|
+
|
24
|
+
* override specific bindings and their logic? e.g. `Namespace#read`
|
25
|
+
* Extend nested representers, e.g. the namespace prefix, when it gets plugged into composition
|
26
|
+
* Easier polymorphic representer
|
27
|
+
|
28
|
+
# XML
|
29
|
+
|
30
|
+
* ditch annoying nokogiri in favor of https://github.com/YorickPeterse/oga
|
31
|
+
|
32
|
+
# Parsing
|
33
|
+
|
34
|
+
* Let bindings have any "xpath"
|
35
|
+
* Allow to parse "wildcard" sections where you have no idea about the property names (and attribute names, eg. with links)
|
36
|
+
|
37
|
+
# Options
|
38
|
+
|
39
|
+
* There should be an easier way to pass a set of options to all nested #to_node decorators.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
representable_attrs.keys.each do |property|
|
43
|
+
options[property.to_sym] = { show_definition: false, namespaces: options[:namespaces] }
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
* Allow passing options to Binding#serialize.
|
48
|
+
serialize(.., options{:exclude => ..})
|
49
|
+
|
50
|
+
|
51
|
+
# wrap, as
|
52
|
+
|
53
|
+
AsWithNamespace( Binding )
|
54
|
+
BUT NOT FOR AsWithNamespace( Binding::Attribute )
|
55
|
+
=> selectively wrap bindings at compile- and runtime
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
* Cleanup the manifest part in Decorator.
|
63
|
+
|
64
|
+
* all property objects should be extended/wrapped so we don't need the switch.
|
65
|
+
|
66
|
+
# Deprecations
|
67
|
+
|
68
|
+
* deprecate instance: { nil } which is superseded by parse_strategy: :sync
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
from_hash, property :band, class: vergessen
|
@@ -47,10 +47,10 @@ module Representable
|
|
47
47
|
NestedBuilder = ->(options) do
|
48
48
|
Module.new do
|
49
49
|
include Representable # FIXME: do we really need this?
|
50
|
-
feature
|
51
|
-
include
|
50
|
+
feature(*options[:_features])
|
51
|
+
include(*options[:_base]) # base when :inherit, or in decorator.
|
52
52
|
|
53
|
-
module_eval
|
53
|
+
module_eval(&options[:_block])
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -96,7 +96,7 @@ module Representable
|
|
96
96
|
If = ->(input, options) { options[:binding].evaluate_option(:if, nil, options) ? input : Pipeline::Stop }
|
97
97
|
|
98
98
|
StopOnExcluded = ->(input, options) do
|
99
|
-
return input unless
|
99
|
+
return input unless options[:options]
|
100
100
|
return input unless props = (options[:options][:exclude] || options[:options][:include])
|
101
101
|
|
102
102
|
res = props.include?(options[:binding].name.to_sym) # false with include: Stop. false with exclude: go!
|
@@ -51,4 +51,4 @@ module Representable
|
|
51
51
|
# Warning: don't rely on AssignAs/AssignName, i am not sure if i leave that as functions.
|
52
52
|
AssignAs = ->(input, options) { options[:as] = As.(input, options); input }
|
53
53
|
AssignName = ->(input, options) { options[:as] = options[:binding].name; input }
|
54
|
-
end
|
54
|
+
end
|
data/lib/representable/xml.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'representable'
|
2
|
-
require 'representable/xml/binding'
|
3
|
-
require 'representable/xml/collection'
|
4
2
|
|
5
3
|
begin
|
6
4
|
require 'nokogiri'
|
@@ -46,10 +44,10 @@ module Representable
|
|
46
44
|
|
47
45
|
# Returns a Nokogiri::XML object representing this object.
|
48
46
|
def to_node(options={})
|
49
|
-
options[:doc]
|
47
|
+
options[:doc] = Nokogiri::XML::Document.new # DISCUSS: why do we need a fresh Document here?
|
50
48
|
root_tag = options[:wrap] || representation_wrap(options)
|
51
49
|
|
52
|
-
create_representation_with(
|
50
|
+
create_representation_with(Node(options[:doc], root_tag.to_s), options, Binding)
|
53
51
|
end
|
54
52
|
|
55
53
|
def to_xml(*args)
|
@@ -73,3 +71,7 @@ module Representable
|
|
73
71
|
end
|
74
72
|
end
|
75
73
|
end
|
74
|
+
|
75
|
+
require "representable/xml/binding"
|
76
|
+
require "representable/xml/collection"
|
77
|
+
require "representable/xml/namespace"
|
@@ -3,6 +3,14 @@ require 'representable/hash/binding.rb'
|
|
3
3
|
|
4
4
|
module Representable
|
5
5
|
module XML
|
6
|
+
module_function
|
7
|
+
def Node(document, name, attributes={})
|
8
|
+
node = Nokogiri::XML::Node.new(name.to_s, document) # Java::OrgW3cDom::DOMException: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
|
9
|
+
|
10
|
+
attributes.each { |k, v| node[k] = v } # TODO: benchmark.
|
11
|
+
node
|
12
|
+
end
|
13
|
+
|
6
14
|
class Binding < Representable::Binding
|
7
15
|
def self.build_for(definition)
|
8
16
|
return Collection.new(definition) if definition.array?
|
@@ -17,7 +25,7 @@ module Representable
|
|
17
25
|
wrap_node = parent
|
18
26
|
|
19
27
|
if wrap = self[:wrap]
|
20
|
-
parent << wrap_node =
|
28
|
+
parent << wrap_node = XML::Node(parent, wrap)
|
21
29
|
end
|
22
30
|
|
23
31
|
wrap_node << serialize_for(fragments, parent, as)
|
@@ -32,12 +40,15 @@ module Representable
|
|
32
40
|
|
33
41
|
# Creates wrapped node for the property.
|
34
42
|
def serialize_for(value, parent, as)
|
35
|
-
node =
|
36
|
-
serialize_node(node, value)
|
43
|
+
node = XML::Node(parent, as) # node doesn't have attr="" attributes!!!
|
44
|
+
serialize_node(node, value, as)
|
37
45
|
end
|
38
46
|
|
39
|
-
def serialize_node(node, value)
|
40
|
-
|
47
|
+
def serialize_node(node, value, as)
|
48
|
+
if typed?
|
49
|
+
value.name = as if as != self[:name]
|
50
|
+
return value
|
51
|
+
end
|
41
52
|
|
42
53
|
node.content = value
|
43
54
|
node
|
@@ -60,11 +71,7 @@ module Representable
|
|
60
71
|
def find_nodes(doc, as)
|
61
72
|
selector = as
|
62
73
|
selector = "#{self[:wrap]}/#{as}" if self[:wrap]
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
def node_for(parent, name)
|
67
|
-
Nokogiri::XML::Node.new(name.to_s, parent.document)
|
74
|
+
doc.xpath(selector) # nodes
|
68
75
|
end
|
69
76
|
|
70
77
|
def content_for(node) # TODO: move this into a ScalarDecorator.
|
@@ -100,8 +107,8 @@ module Representable
|
|
100
107
|
class Hash < Collection
|
101
108
|
def serialize_for(value, parent, as)
|
102
109
|
set_for(parent, value.collect do |k, v|
|
103
|
-
node =
|
104
|
-
serialize_node(node, v)
|
110
|
+
node = XML::Node(parent, k)
|
111
|
+
serialize_node(node, v, as)
|
105
112
|
end)
|
106
113
|
end
|
107
114
|
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Representable::XML
|
2
|
+
# Experimental!
|
3
|
+
# Best explanation so far: http://books.xmlschemata.org/relaxng/relax-CHP-11-SECT-1.html
|
4
|
+
#
|
5
|
+
# Note: This module doesn't work with JRuby because Nokogiri uses a completely
|
6
|
+
# different implementation in Java which has other requirements that we couldn't fulfil.
|
7
|
+
# Please wait for Representable 4 where we replace Nokogiri with Oga.
|
8
|
+
module Namespace
|
9
|
+
def self.included(includer)
|
10
|
+
includer.extend(DSL)
|
11
|
+
end
|
12
|
+
|
13
|
+
module DSL
|
14
|
+
def namespace(namespace)
|
15
|
+
representable_attrs.options[:local_namespace] = namespace
|
16
|
+
representable_attrs.options[:namespace_mappings] ||= {}
|
17
|
+
representable_attrs.options[:namespace_mappings][namespace] = nil # this might get overwritten via #namespace_def later.
|
18
|
+
end
|
19
|
+
|
20
|
+
def namespace_def(mapping)
|
21
|
+
namespace_defs.merge!(mapping.invert)
|
22
|
+
end
|
23
|
+
|
24
|
+
# :private:
|
25
|
+
def namespace_defs
|
26
|
+
representable_attrs.options[:namespace_mappings] ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def property(name, options={})
|
30
|
+
uri = representable_attrs.options[:local_namespace] # per default, a property belongs to the local namespace.
|
31
|
+
options[:namespace] ||= uri # don't override if already set.
|
32
|
+
|
33
|
+
# a nested representer is automatically assigned "its" local namespace. It's like saying
|
34
|
+
# property :author, namespace: "http://ns/author" do ... end
|
35
|
+
|
36
|
+
super.tap do |dfn|
|
37
|
+
if dfn.typed? # FIXME: ouch, this should be doable with property's API to hook into the creation process.
|
38
|
+
dfn.merge!( namespace: dfn.representer_module.representable_attrs.options[:local_namespace] )
|
39
|
+
|
40
|
+
update_namespace_defs!(namespace_defs)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# :private:
|
46
|
+
# super ugly hack
|
47
|
+
# recursively injects the namespace_defs into all representers of this tree. will be done better in 4.0.
|
48
|
+
def update_namespace_defs!(namespace_defs)
|
49
|
+
representable_attrs.each do |dfn|
|
50
|
+
dfn.merge!(namespace_defs: namespace_defs) # this only helps with scalars
|
51
|
+
|
52
|
+
if dfn.typed?
|
53
|
+
representer = Class.new(dfn.representer_module) # don't pollute classes.
|
54
|
+
representer.update_namespace_defs!(namespace_defs)
|
55
|
+
dfn.merge!(extend: representer)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module AsWithNamespace
|
62
|
+
def write(doc, fragment, as)
|
63
|
+
super(doc, fragment, prefixed(self, as))
|
64
|
+
end
|
65
|
+
|
66
|
+
# FIXME: this is shit, the NestedOptions is executed too late here!
|
67
|
+
def read(node, as)
|
68
|
+
super(node, prefixed(self, as))
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def prefixed(dfn, as)
|
73
|
+
uri = dfn[:namespace] # this is generic behavior and per property
|
74
|
+
prefix = dfn[:namespace_defs][uri]
|
75
|
+
as = Namespace::Namespaced(prefix, as)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# FIXME: some "bug" in Representable's XML doesn't consider the container tag, so we could theoretically pick the
|
80
|
+
# wrong namespaced tag here :O
|
81
|
+
def from_node(node, options={})
|
82
|
+
super
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_node(options={})
|
86
|
+
local_uri = representable_attrs.options[:local_namespace] # every decorator MUST have a local namespace.
|
87
|
+
prefix = self.class.namespace_defs[local_uri]
|
88
|
+
|
89
|
+
root_tag = [prefix, representation_wrap(options)].compact.join(":")
|
90
|
+
|
91
|
+
options = { wrap: root_tag }.merge(options)
|
92
|
+
|
93
|
+
# TODO: there should be an easier way to pass a set of options to all nested #to_node decorators.
|
94
|
+
representable_attrs.keys.each do |property|
|
95
|
+
options[property.to_sym] = { show_definition: false, namespaces: options[:namespaces] }
|
96
|
+
end
|
97
|
+
|
98
|
+
super(options).tap do |node|
|
99
|
+
add_namespace_definitions!(node, self.class.namespace_defs) unless options[:show_definition] == false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# "Physically" add `xmlns` attributes to `node`.
|
104
|
+
def add_namespace_definitions!(node, namespaces)
|
105
|
+
namespaces.each do |uri, prefix|
|
106
|
+
prefix = prefix.nil? ? nil : prefix.to_s
|
107
|
+
node.add_namespace_definition(prefix, uri)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.Namespaced(prefix, name)
|
112
|
+
[ prefix, name ].compact.join(":")
|
113
|
+
end
|
114
|
+
|
115
|
+
# FIXME: this is a PoC, we need a better API to inject code.
|
116
|
+
def representable_map(options, format)
|
117
|
+
super.tap do |map|
|
118
|
+
map.each { |bin| bin.extend(AsWithNamespace) unless bin.is_a?(Binding::Attribute) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/representable.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.platform = Gem::Platform::RUBY
|
10
10
|
spec.authors = ["Nick Sutterer"]
|
11
11
|
spec.email = ["apotonick@gmail.com"]
|
12
|
-
spec.homepage = "https://github.com/
|
12
|
+
spec.homepage = "https://github.com/trailblazer/representable/"
|
13
13
|
spec.summary = %q{Renders and parses JSON/XML/YAML documents from and to Ruby objects. Includes plain properties, collections, nesting, coercion and more.}
|
14
14
|
spec.description = spec.summary
|
15
15
|
|
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_dependency "declarative-option", "< 0.2.0"
|
27
27
|
|
28
28
|
spec.add_development_dependency "rake"
|
29
|
-
spec.add_development_dependency "test_xml", "0.1.6"
|
29
|
+
spec.add_development_dependency "test_xml", ">= 0.1.6"
|
30
30
|
spec.add_development_dependency "minitest"
|
31
31
|
spec.add_development_dependency "virtus"
|
32
32
|
spec.add_development_dependency "multi_json"
|
data/test/as_test.rb
CHANGED
@@ -7,8 +7,8 @@ class AsTest < MiniTest::Spec
|
|
7
7
|
# :yaml => [Representable::YAML, "---\nsong:\n name: Alive\n", "---\nsong:\n name: You've Taken Everything\n"],
|
8
8
|
) do |format, mod, input, output|
|
9
9
|
|
10
|
-
let
|
11
|
-
let
|
10
|
+
let(:song) { representer.prepare(Song.new("Revolution")) }
|
11
|
+
let(:format) { format }
|
12
12
|
|
13
13
|
|
14
14
|
describe "as: with :symbol" do
|
data/test/binding_test.rb
CHANGED
@@ -2,10 +2,10 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class BindingTest < MiniTest::Spec
|
4
4
|
Binding = Representable::Binding
|
5
|
-
let
|
5
|
+
let(:render_nil_definition) { Representable::Definition.new(:song, :render_nil => true) }
|
6
6
|
|
7
7
|
describe "#skipable_empty_value?" do
|
8
|
-
let
|
8
|
+
let(:binding) { Binding.new(render_nil_definition) }
|
9
9
|
|
10
10
|
# don't skip when present.
|
11
11
|
it { binding.skipable_empty_value?("Disconnect, Disconnect").must_equal false }
|
@@ -22,8 +22,8 @@ class BindingTest < MiniTest::Spec
|
|
22
22
|
|
23
23
|
|
24
24
|
describe "#default_for" do
|
25
|
-
let
|
26
|
-
let
|
25
|
+
let(:definition) { Representable::Definition.new(:song, :default => "Insider") }
|
26
|
+
let(:binding) { Binding.new(definition) }
|
27
27
|
|
28
28
|
# return value when value present.
|
29
29
|
it { binding.default_for("Black And Blue").must_equal "Black And Blue" }
|
@@ -35,12 +35,12 @@ class BindingTest < MiniTest::Spec
|
|
35
35
|
it { binding.default_for(nil).must_equal "Insider" }
|
36
36
|
|
37
37
|
# return nil when value nil and render_nil: true.
|
38
|
-
it { Binding.new(render_nil_definition).default_for(nil).
|
38
|
+
it { Binding.new(render_nil_definition).default_for(nil).must_be_nil }
|
39
39
|
|
40
40
|
# return nil when value nil and render_nil: true, even when :default is set" do
|
41
|
-
it { Binding.new(Representable::Definition.new(:song, :render_nil => true, :default => "The Quest")).default_for(nil).
|
41
|
+
it { Binding.new(Representable::Definition.new(:song, :render_nil => true, :default => "The Quest")).default_for(nil).must_be_nil }
|
42
42
|
|
43
43
|
# return nil if no :default
|
44
|
-
it { Binding.new(Representable::Definition.new(:song)).default_for(nil).
|
44
|
+
it { Binding.new(Representable::Definition.new(:song)).default_for(nil).must_be_nil }
|
45
45
|
end
|
46
46
|
end
|