representable 0.0.1.alpha1 → 0.0.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.
- data/README.rdoc +58 -153
- data/lib/representable.rb +18 -42
- data/lib/representable/bindings/json_bindings.rb +69 -0
- data/lib/representable/bindings/xml_bindings.rb +152 -0
- data/lib/representable/definition.rb +1 -12
- data/lib/representable/json.rb +66 -0
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml.rb +32 -38
- data/representable.gemspec +3 -2
- data/test/bindings_test.rb +110 -0
- data/test/json_test.rb +130 -0
- data/test/{roxml_test.rb → representable_test.rb} +28 -9
- data/test/test_helper.rb +2 -0
- data/test/xml_test.rb +192 -0
- metadata +32 -105
- data/History.txt +0 -354
- data/TODO +0 -37
- data/VERSION +0 -1
- data/examples/amazon.rb +0 -35
- data/examples/current_weather.rb +0 -27
- data/examples/dashed_elements.rb +0 -20
- data/examples/library.rb +0 -40
- data/examples/posts.rb +0 -27
- data/examples/rails.rb +0 -70
- data/examples/twitter.rb +0 -37
- data/examples/xml/active_record.xml +0 -70
- data/examples/xml/amazon.xml +0 -133
- data/examples/xml/current_weather.xml +0 -89
- data/examples/xml/dashed_elements.xml +0 -52
- data/examples/xml/posts.xml +0 -23
- data/examples/xml/twitter.xml +0 -422
- data/lib/representable/references.rb +0 -153
- data/spec/definition_spec.rb +0 -495
- data/spec/examples/active_record_spec.rb +0 -41
- data/spec/examples/amazon_spec.rb +0 -54
- data/spec/examples/current_weather_spec.rb +0 -37
- data/spec/examples/dashed_elements_spec.rb +0 -20
- data/spec/examples/library_spec.rb +0 -46
- data/spec/examples/post_spec.rb +0 -24
- data/spec/examples/twitter_spec.rb +0 -32
- data/spec/roxml_integration_test.rb +0 -289
- data/spec/roxml_spec.rb +0 -372
- data/spec/shared_specs.rb +0 -15
- data/spec/spec_helper.rb +0 -5
- data/spec/support/libxml.rb +0 -3
- data/spec/support/nokogiri.rb +0 -3
- data/spec/xml/array_spec.rb +0 -36
- data/spec/xml/attributes_spec.rb +0 -71
- data/spec/xml/encoding_spec.rb +0 -53
- data/spec/xml/namespace_spec.rb +0 -270
- data/spec/xml/namespaces_spec.rb +0 -67
- data/spec/xml/object_spec.rb +0 -82
- data/spec/xml/parser_spec.rb +0 -21
- data/spec/xml/text_spec.rb +0 -71
- data/test/fixtures/book_malformed.xml +0 -5
- data/test/fixtures/book_pair.xml +0 -8
- data/test/fixtures/book_text_with_attribute.xml +0 -5
- data/test/fixtures/book_valid.xml +0 -5
- data/test/fixtures/book_with_authors.xml +0 -7
- data/test/fixtures/book_with_contributions.xml +0 -9
- data/test/fixtures/book_with_contributors.xml +0 -7
- data/test/fixtures/book_with_contributors_attrs.xml +0 -7
- data/test/fixtures/book_with_default_namespace.xml +0 -9
- data/test/fixtures/book_with_depth.xml +0 -6
- data/test/fixtures/book_with_octal_pages.xml +0 -4
- data/test/fixtures/book_with_publisher.xml +0 -7
- data/test/fixtures/book_with_wrapped_attr.xml +0 -3
- data/test/fixtures/dictionary_of_attr_name_clashes.xml +0 -8
- data/test/fixtures/dictionary_of_attrs.xml +0 -6
- data/test/fixtures/dictionary_of_guarded_names.xml +0 -6
- data/test/fixtures/dictionary_of_mixeds.xml +0 -4
- data/test/fixtures/dictionary_of_name_clashes.xml +0 -10
- data/test/fixtures/dictionary_of_names.xml +0 -4
- data/test/fixtures/dictionary_of_texts.xml +0 -10
- data/test/fixtures/library.xml +0 -30
- data/test/fixtures/library_uppercase.xml +0 -30
- data/test/fixtures/muffins.xml +0 -3
- data/test/fixtures/nameless_ageless_youth.xml +0 -2
- data/test/fixtures/node_with_attr_name_conflicts.xml +0 -1
- data/test/fixtures/node_with_name_conflicts.xml +0 -4
- data/test/fixtures/numerology.xml +0 -4
- data/test/fixtures/person.xml +0 -1
- data/test/fixtures/person_with_guarded_mothers.xml +0 -13
- data/test/fixtures/person_with_mothers.xml +0 -10
- data/test/mocks/dictionaries.rb +0 -57
- data/test/mocks/mocks.rb +0 -279
- data/test/support/fixtures.rb +0 -11
- data/test/unit/definition_test.rb +0 -235
- data/test/unit/deprecations_test.rb +0 -24
- data/test/unit/to_xml_test.rb +0 -81
- data/test/unit/xml_attribute_test.rb +0 -39
- data/test/unit/xml_block_test.rb +0 -81
- data/test/unit/xml_bool_test.rb +0 -122
- data/test/unit/xml_convention_test.rb +0 -150
- data/test/unit/xml_hash_test.rb +0 -115
- data/test/unit/xml_initialize_test.rb +0 -49
- data/test/unit/xml_name_test.rb +0 -141
- data/test/unit/xml_namespace_test.rb +0 -31
- data/test/unit/xml_object_test.rb +0 -206
- data/test/unit/xml_required_test.rb +0 -94
- data/test/unit/xml_text_test.rb +0 -71
- data/website/index.html +0 -98
@@ -43,7 +43,7 @@ module Representable
|
|
43
43
|
elsif opts[:from] == :namespace
|
44
44
|
opts[:from] = '*'
|
45
45
|
@sought_type = :namespace
|
46
|
-
elsif opts[:from].to_s.
|
46
|
+
elsif opts[:from].to_s =~ /^@/ # FIXME: move me to xml.
|
47
47
|
@sought_type = :attr
|
48
48
|
opts[:from].sub!('@', '')
|
49
49
|
end
|
@@ -65,7 +65,6 @@ module Representable
|
|
65
65
|
sought_type.is_a?(Class)
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
68
|
def name?
|
70
69
|
@name == '*'
|
71
70
|
end
|
@@ -88,16 +87,6 @@ module Representable
|
|
88
87
|
|
89
88
|
value
|
90
89
|
end
|
91
|
-
|
92
|
-
def to_ref
|
93
|
-
case sought_type
|
94
|
-
when :attr then XMLAttributeRef
|
95
|
-
when :text then XMLTextRef
|
96
|
-
when :namespace then XMLNameSpaceRef
|
97
|
-
when Symbol then raise ArgumentError, "Invalid type argument #{sought_type}"
|
98
|
-
else XMLObjectRef
|
99
|
-
end.new(self)
|
100
|
-
end
|
101
90
|
|
102
91
|
private
|
103
92
|
def extract_type(as)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'representable/bindings/json_bindings'
|
3
|
+
|
4
|
+
module Representable
|
5
|
+
module JSON
|
6
|
+
BINDING_FOR_TYPE = { # TODO: refactor #representable_accessor for better extendability.
|
7
|
+
:text => TextBinding,
|
8
|
+
}
|
9
|
+
def self.binding_for_definition(definition)
|
10
|
+
(BINDING_FOR_TYPE[definition.sought_type] or ObjectBinding).new(definition)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
include Representable
|
16
|
+
include InstanceMethods
|
17
|
+
end
|
18
|
+
base.extend ClassMethods # DISCUSS: do that dynamically?
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
# Creates a new Ruby object from XML using mapping information declared in the class.
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
# book = Book.from_xml("<book><name>Beyond Java</name></book>")
|
26
|
+
def from_json(data, options={})
|
27
|
+
# DISCUSS: extract #from_json call in Bindings to this place.
|
28
|
+
data = ::JSON[data] if data.is_a?(String) # DISCUSS: #from_json sometimes receives a string (in nestings).
|
29
|
+
data ||= {}
|
30
|
+
|
31
|
+
data = data[representation_name] unless options[:wrap] == false
|
32
|
+
|
33
|
+
create_from_json.tap do |inst|
|
34
|
+
refs = representable_attrs.map {|attr| JSON.binding_for_definition(attr) }
|
35
|
+
|
36
|
+
refs.each do |ref|
|
37
|
+
value = ref.value_in(data)
|
38
|
+
|
39
|
+
inst.send(ref.definition.setter, value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def create_from_json(*args)
|
46
|
+
new(*args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module InstanceMethods # :nodoc:
|
51
|
+
# Returns a Nokogiri::XML object representing this object.
|
52
|
+
def to_json(options={})
|
53
|
+
attributes = {}.tap do |root|
|
54
|
+
refs = self.class.representable_attrs.map {|attr| JSON.binding_for_definition(attr) }
|
55
|
+
|
56
|
+
refs.each do |ref|
|
57
|
+
value = public_send(ref.accessor) # DISCUSS: eventually move back to Ref.
|
58
|
+
ref.update_json(root, value) if value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
options[:wrap] == false ? attributes : {self.class.representation_name => attributes}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end # Xml
|
66
|
+
end
|
data/lib/representable/xml.rb
CHANGED
@@ -1,50 +1,44 @@
|
|
1
|
+
require 'representable'
|
2
|
+
require 'representable/bindings/xml_bindings'
|
3
|
+
|
1
4
|
module Representable
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
representable_accessor(*args)
|
5
|
+
module XML
|
6
|
+
BINDING_FOR_TYPE = {
|
7
|
+
:attr => AttributeBinding,
|
8
|
+
:text => TextBinding,
|
9
|
+
:namespace=> NamespaceBinding,
|
10
|
+
}
|
11
|
+
|
12
|
+
def self.binding_for_definition(definition)
|
13
|
+
(BINDING_FOR_TYPE[definition.sought_type] or ObjectBinding).new(definition)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.included(base)
|
17
|
+
base.class_eval do
|
18
|
+
include Representable
|
19
|
+
include InstanceMethods
|
20
|
+
extend ClassMethods
|
19
21
|
end
|
20
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
class Definition < Representable::Definition
|
25
|
+
# FIXME: extract xml-specific from Definition.
|
21
26
|
end
|
22
27
|
|
23
28
|
module ClassMethods
|
29
|
+
def definition_class
|
30
|
+
Definition
|
31
|
+
end
|
32
|
+
|
33
|
+
# Creates a new Ruby object from XML using mapping information declared in the class.
|
24
34
|
#
|
25
|
-
#
|
26
|
-
# annotated in the class.
|
27
|
-
#
|
28
|
-
# The input data is either an XML::Node, String, Pathname, or File representing
|
29
|
-
# the XML document.
|
30
|
-
#
|
31
|
-
# Example
|
32
|
-
# book = Book.from_xml(File.read("book.xml"))
|
33
|
-
# or
|
35
|
+
# Example:
|
34
36
|
# book = Book.from_xml("<book><name>Beyond Java</name></book>")
|
35
|
-
#
|
36
|
-
# _initialization_args_ passed into from_xml will be passed into
|
37
|
-
# the object's .new, prior to populating the xml_attrs.
|
38
|
-
#
|
39
|
-
# After the instatiation and xml population
|
40
|
-
#
|
41
|
-
# See also: xml_initialize
|
42
|
-
#
|
43
37
|
def from_xml(data, *args)
|
44
38
|
xml = Nokogiri::XML::Node.from(data)
|
45
39
|
|
46
40
|
create_from_xml(*args).tap do |inst|
|
47
|
-
refs = representable_attrs.map {|attr| attr
|
41
|
+
refs = representable_attrs.map {|attr| XML.binding_for_definition(attr) }
|
48
42
|
|
49
43
|
refs.each do |ref|
|
50
44
|
value = ref.value_in(xml)
|
@@ -61,12 +55,12 @@ module Representable
|
|
61
55
|
end
|
62
56
|
|
63
57
|
module InstanceMethods # :nodoc:
|
64
|
-
# Returns
|
58
|
+
# Returns a Nokogiri::XML object representing this object.
|
65
59
|
def to_xml(params={})
|
66
60
|
params.reverse_merge!(:name => self.class.representation_name)
|
67
61
|
|
68
62
|
Nokogiri::XML::Node.new(params[:name].to_s, Nokogiri::XML::Document.new).tap do |root|
|
69
|
-
refs = self.class.representable_attrs.map {|attr| attr
|
63
|
+
refs = self.class.representable_attrs.map {|attr| XML.binding_for_definition(attr) }
|
70
64
|
|
71
65
|
refs.each do |ref|
|
72
66
|
value = public_send(ref.accessor) # DISCUSS: eventually move back to Ref.
|
data/representable.gemspec
CHANGED
@@ -12,17 +12,18 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.email = ["apotonick@gmail.com"]
|
13
13
|
s.homepage = "http://representable.apotomo.de"
|
14
14
|
s.summary = %q{Maps representation documents from and to Ruby objects. Includes XML and JSON support, plain properties and compositions.}
|
15
|
-
s.description = %q{
|
15
|
+
s.description = %q{Maps representation documents from and to Ruby objects. Includes XML and JSON support, plain properties and compositions.}
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_dependency "activesupport"
|
22
|
+
s.add_dependency "activesupport"
|
23
23
|
s.add_dependency "hooks"
|
24
24
|
s.add_dependency "nokogiri"
|
25
25
|
s.add_dependency "i18n"
|
26
|
+
s.add_dependency "json"
|
26
27
|
|
27
28
|
s.add_development_dependency "rspec"
|
28
29
|
s.add_development_dependency "test_xml"
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ReferenceTest < 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
|
+
describe "TextRef#value_in" do
|
16
|
+
def parse_xml(xml); Nokogiri::XML::Node.from(xml); end
|
17
|
+
|
18
|
+
before do
|
19
|
+
@ref = Representable::XML::TextBinding.new(Representable::Definition.new(:song))
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns found value" do
|
23
|
+
assert_equal "Unkoil", @ref.value_in(parse_xml("<a><song>Unkoil</song></a>"))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DefinitionTest < MiniTest::Spec
|
29
|
+
describe "generic API" do
|
30
|
+
before do
|
31
|
+
@def = Representable::Definition.new(:songs)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "responds to #typed?" do
|
35
|
+
assert ! @def.typed?
|
36
|
+
assert Representable::Definition.new(:songs, :as => Hash).typed?
|
37
|
+
assert Representable::Definition.new(:songs, :as => [Hash]).typed?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
describe "#apply" do
|
43
|
+
it "works with a single item" do
|
44
|
+
@d = Representable::Definition.new(:song)
|
45
|
+
assert_equal 2, @d.apply(1) { |v| v+1 }
|
46
|
+
end
|
47
|
+
|
48
|
+
it "works with collection" do
|
49
|
+
@d = Representable::Definition.new(:song, :as => [])
|
50
|
+
assert_equal [2,3,4], @d.apply([1,2,3]) { |v| v+1 }
|
51
|
+
end
|
52
|
+
|
53
|
+
it "skips with collection and nil" do
|
54
|
+
@d = Representable::Definition.new(:song, :as => [])
|
55
|
+
assert_equal nil, @d.apply(nil) { |v| v+1 }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe ":as => []" do
|
60
|
+
before do
|
61
|
+
@def = Representable::Definition.new(:songs, :as => [], :tag => :song)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "responds to #accessor" do
|
65
|
+
assert_equal "songs", @def.accessor
|
66
|
+
end
|
67
|
+
|
68
|
+
it "responds to #array?" do
|
69
|
+
assert @def.array?
|
70
|
+
end
|
71
|
+
|
72
|
+
it "responds to #name" do
|
73
|
+
assert_equal "songs", @def.accessor
|
74
|
+
end
|
75
|
+
|
76
|
+
it "responds to #instance_variable_name" do
|
77
|
+
assert_equal :"@songs", @def.instance_variable_name
|
78
|
+
end
|
79
|
+
|
80
|
+
it "responds to #setter" do
|
81
|
+
assert_equal :"songs=", @def.setter
|
82
|
+
end
|
83
|
+
|
84
|
+
it "responds to #sought_type" do
|
85
|
+
assert_equal :text, @def.sought_type
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
describe ":as => [Item]" do
|
91
|
+
before do
|
92
|
+
@def = Representable::Definition.new(:songs, :as => [Hash])
|
93
|
+
end
|
94
|
+
|
95
|
+
it "responds to #sought_type" do
|
96
|
+
assert_equal Hash, @def.sought_type
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
describe ":as => Item" do
|
102
|
+
before do
|
103
|
+
@def = Representable::Definition.new(:songs, :as => Hash)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "responds to #sought_type" do
|
107
|
+
assert_equal Hash, @def.sought_type
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/test/json_test.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'representable/json'
|
3
|
+
|
4
|
+
module JsonTest
|
5
|
+
class APITest < MiniTest::Spec
|
6
|
+
Json = Representable::JSON
|
7
|
+
Def = Representable::Definition
|
8
|
+
|
9
|
+
describe "Xml module" do
|
10
|
+
describe "#binding_for_definition" do
|
11
|
+
it "returns ObjectBinding" do
|
12
|
+
assert_kind_of Json::ObjectBinding, Json.binding_for_definition(Def.new(:band, :as => Hash))
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns TextBinding" do
|
16
|
+
assert_kind_of Json::TextBinding, Json.binding_for_definition(Def.new(:band))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class PropertyTest < MiniTest::Spec
|
23
|
+
describe "property :name" do
|
24
|
+
class Band
|
25
|
+
include Representable::JSON
|
26
|
+
representable_property :name
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#from_json creates correct accessors" do
|
30
|
+
band = Band.from_json({:band => {:name => "Bombshell Rocks"}}.to_json)
|
31
|
+
assert_equal "Bombshell Rocks", band.name
|
32
|
+
end
|
33
|
+
|
34
|
+
it "#to_json serializes correctly" do
|
35
|
+
band = Band.new
|
36
|
+
band.name = "Cigar"
|
37
|
+
|
38
|
+
assert_equal "{\"band\"=>{\"name\"=>\"Cigar\"}}", band.to_json.to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "property :name, :as => []" do
|
43
|
+
class CD
|
44
|
+
include Representable::JSON
|
45
|
+
representable_property :songs, :as => []
|
46
|
+
end
|
47
|
+
|
48
|
+
it "#from_json creates correct accessors" do
|
49
|
+
cd = CD.from_json({:cd => {:songs => ["Out in the cold", "Microphone"]}}.to_json)
|
50
|
+
assert_equal ["Out in the cold", "Microphone"], cd.songs
|
51
|
+
end
|
52
|
+
|
53
|
+
it "#to_json serializes correctly" do
|
54
|
+
cd = CD.new
|
55
|
+
cd.songs = ["Out in the cold", "Microphone"]
|
56
|
+
|
57
|
+
assert_equal "{\"cd\"=>{\"songs\"=>[\"Out in the cold\", \"Microphone\"]}}", cd.to_json.to_s
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class TypedPropertyTest < MiniTest::Spec
|
63
|
+
describe ":as => Item" do
|
64
|
+
class Label
|
65
|
+
include Representable::JSON
|
66
|
+
representable_property :name
|
67
|
+
end
|
68
|
+
|
69
|
+
class Album
|
70
|
+
include Representable::JSON
|
71
|
+
representable_property :label, :as => Label
|
72
|
+
end
|
73
|
+
|
74
|
+
it "#from_json creates one Item instance" do
|
75
|
+
album = Album.from_json({:album => {:label => "Fat Wreck"}}.to_json)
|
76
|
+
assert_equal "Bad Religion", album.label.name
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#to_json" do
|
80
|
+
it "serializes" do
|
81
|
+
label = Label.new; label.name = "Fat Wreck"
|
82
|
+
album = Album.new; album.label = label
|
83
|
+
|
84
|
+
assert_equal "{\"album\"=>{\"label\"=>{\"name\"=>\"Fat Wreck\"}}}", album.to_json.to_s
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
class CollectionTest < MiniTest::Spec
|
92
|
+
describe ":as => [Band]" do
|
93
|
+
class Band
|
94
|
+
include Representable::JSON
|
95
|
+
representable_property :name
|
96
|
+
|
97
|
+
def initialize(name="")
|
98
|
+
self.name = name
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Compilation
|
103
|
+
include Representable::JSON
|
104
|
+
representable_property :bands, :as => [Band]
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#from_json" do
|
108
|
+
it "pushes collection items to array" do
|
109
|
+
cd = Compilation.from_json({:compilation => {:bands => [
|
110
|
+
{:name => "Cobra Skulls"},
|
111
|
+
{:name => "Diesel Boy"}]}}.to_json)
|
112
|
+
assert_equal ["Cobra Skulls", "Diesel Boy"], cd.bands.map(&:name).sort
|
113
|
+
end
|
114
|
+
|
115
|
+
it "collections can be empty" do
|
116
|
+
cd = Compilation.from_json({:compilation => {}}.to_json)
|
117
|
+
assert_equal [], cd.bands
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "responds to #to_json" do
|
122
|
+
cd = Compilation.new
|
123
|
+
cd.bands = [Band.new("Diesel Boy"), Band.new("Bad Religion")]
|
124
|
+
|
125
|
+
assert_equal "{\"compilation\"=>{\"bands\"=>[{\"name\"=>\"Diesel Boy\"}, {\"name\"=>\"Bad Religion\"}]}}", cd.to_json.to_s
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|