roar 0.9.0 → 0.9.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/CHANGES.markdown +5 -0
- data/Rakefile +1 -1
- data/lib/roar/rails/test_case.rb +51 -25
- data/lib/roar/representer.rb +0 -31
- data/lib/roar/representer/feature/hypermedia.rb +4 -4
- data/lib/roar/representer/json.rb +1 -0
- data/lib/roar/representer/xml.rb +3 -2
- data/lib/roar/version.rb +1 -1
- data/roar.gemspec +1 -2
- data/test/http_verbs_feature_test.rb +9 -1
- data/test/hypermedia_feature_test.rb +18 -7
- data/test/json_representer_test.rb +5 -2
- data/test/representer_test.rb +3 -22
- data/test/test_helper.rb +10 -0
- data/test/xml_representer_test.rb +12 -12
- metadata +12 -28
- data/lib/roar/representer/feature/model_representing.rb +0 -80
- data/test/model_representing_test.rb +0 -119
data/CHANGES.markdown
CHANGED
data/Rakefile
CHANGED
data/lib/roar/rails/test_case.rb
CHANGED
@@ -1,12 +1,61 @@
|
|
1
|
-
require 'test_xml/test_unit'
|
1
|
+
#require 'test_xml/test_unit'
|
2
|
+
require 'action_controller/test_case'
|
2
3
|
|
3
|
-
|
4
|
+
module Roar::Rails
|
5
|
+
module TestCase
|
6
|
+
def process(action, *args)
|
7
|
+
raise
|
8
|
+
if args.first.is_a?(String)
|
9
|
+
puts "YO"
|
10
|
+
request.env['RAW_POST_DATA'] = args.shift
|
11
|
+
method = args.pop
|
12
|
+
args << nil
|
13
|
+
args << method
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_response(status, headers={}) # FIXME: allow message.
|
20
|
+
super
|
21
|
+
|
22
|
+
if headers.is_a?(Hash)
|
23
|
+
assert_headers(headers)
|
24
|
+
else
|
25
|
+
assert_body(headers)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def assert_headers(headers)
|
30
|
+
headers.each_pair do |k,v|
|
31
|
+
assert_equal v, @response.headers[k]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_body(body, options={})
|
36
|
+
return assert_xml_equal body, @response.body if options[:format] == :xml # FIXME: how do we know whether assert_xml is appropriate?
|
37
|
+
assert_equal body, @response.body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
ActionController::TestCase::Behavior.class_eval do
|
4
44
|
# FIXME: ugly monkey-patching.
|
5
45
|
# TODO: test:
|
6
46
|
# put :create
|
7
47
|
# put :create, :format => :xml
|
8
48
|
# put :create, "<order/>", :format => :xml
|
9
49
|
# put :create, "<order/>"
|
50
|
+
|
51
|
+
|
52
|
+
include Roar::Rails::TestCase
|
53
|
+
end
|
54
|
+
|
55
|
+
RSpec::Rails::ControllerExampleGroup.class_eval do
|
56
|
+
#include Roar::Rails::TestCase
|
57
|
+
# FIXME: include module!
|
58
|
+
|
10
59
|
def process(action, *args)
|
11
60
|
if args.first.is_a?(String)
|
12
61
|
request.env['RAW_POST_DATA'] = args.shift
|
@@ -14,30 +63,7 @@ ActionController::TestCase.class_eval do
|
|
14
63
|
args << nil
|
15
64
|
args << method
|
16
65
|
end
|
17
|
-
|
18
|
-
super
|
19
|
-
end
|
20
66
|
|
21
|
-
def assert_response(status, headers={}) # FIXME: allow message.
|
22
67
|
super
|
23
|
-
|
24
|
-
if headers.is_a?(Hash)
|
25
|
-
assert_headers(headers)
|
26
|
-
else
|
27
|
-
assert_body(headers)
|
28
|
-
end
|
29
68
|
end
|
30
|
-
|
31
|
-
def assert_headers(headers)
|
32
|
-
headers.each_pair do |k,v|
|
33
|
-
assert_equal v, @response.headers[k]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def assert_body(body, options={})
|
38
|
-
return assert_xml_equal body, @response.body if options[:format] == :xml # FIXME: how do we know whether assert_xml is appropriate?
|
39
|
-
assert_equal body, @response.body
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
69
|
end
|
data/lib/roar/representer.rb
CHANGED
@@ -5,40 +5,9 @@ module Roar
|
|
5
5
|
def self.included(base)
|
6
6
|
base.class_eval do
|
7
7
|
include Representable
|
8
|
-
extend ClassMethods
|
9
8
|
end
|
10
9
|
end
|
11
10
|
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
# Creates a representer instance and fills it with +attributes+.
|
15
|
-
# DISCUSS: remove.
|
16
|
-
def from_attributes(attributes) # DISCUSS: better move to #new? how do we handle the original #new then?
|
17
|
-
new.tap do |representer|
|
18
|
-
yield representer if block_given?
|
19
|
-
attributes.each { |p,v| representer.public_send("#{p}=", v) }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
# Convert representer's attributes to a nested attributes hash.
|
26
|
-
def to_attributes
|
27
|
-
{}.tap do |attributes|
|
28
|
-
self.class.representable_attrs.each do |definition|
|
29
|
-
value = public_send(definition.getter)
|
30
|
-
|
31
|
-
if definition.typed?
|
32
|
-
value = definition.apply(value) do |v|
|
33
|
-
v.to_attributes # applied to each typed attribute (even in collections).
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
attributes[definition.name] = value
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
11
|
private
|
43
12
|
def before_serialize(*)
|
44
13
|
end
|
@@ -38,10 +38,10 @@ module Roar
|
|
38
38
|
hyperlink_class = links_def.sought_type
|
39
39
|
|
40
40
|
links_def.rel2block.each do |link|
|
41
|
-
links.update_link(hyperlink_class.
|
42
|
-
|
43
|
-
|
44
|
-
)
|
41
|
+
links.update_link(hyperlink_class.new.tap do |hyperlink| # create Hyperlink representer.
|
42
|
+
hyperlink.rel = link[:rel]
|
43
|
+
hyperlink.href = run_link_block(link[:block])
|
44
|
+
end)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
data/lib/roar/representer/xml.rb
CHANGED
@@ -50,12 +50,13 @@ module Roar
|
|
50
50
|
# Encapsulates a hypermedia <link ...>.
|
51
51
|
class Hyperlink
|
52
52
|
# TODO: make XML a module to include in Hyperlink < Base.
|
53
|
+
attr_accessor :rel, :href
|
53
54
|
include XML
|
54
55
|
|
55
56
|
self.representation_wrap = :link
|
56
57
|
|
57
|
-
property :rel, :from => "
|
58
|
-
property :href, :from => "
|
58
|
+
property :rel, :from => "rel", :attribute => true
|
59
|
+
property :href, :from => "href", :attribute => true
|
59
60
|
end
|
60
61
|
|
61
62
|
end
|
data/lib/roar/version.rb
CHANGED
data/roar.gemspec
CHANGED
@@ -19,8 +19,7 @@ Gem::Specification.new do |s|
|
|
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_runtime_dependency "representable", "~> 0.
|
23
|
-
s.add_runtime_dependency "hooks", "~> 0.1.4"
|
22
|
+
s.add_runtime_dependency "representable", "~> 1.0.1"
|
24
23
|
|
25
24
|
s.add_development_dependency "test_xml"
|
26
25
|
s.add_development_dependency "minitest", "~> 1.6.0"
|
@@ -10,19 +10,27 @@ class HttpVerbsTest < MiniTest::Spec
|
|
10
10
|
property :label
|
11
11
|
end
|
12
12
|
|
13
|
+
# keep this class clear of Roar modules.
|
14
|
+
class Band
|
15
|
+
attr_accessor :name, :label
|
16
|
+
end
|
17
|
+
|
18
|
+
|
13
19
|
describe "HttpVerbs" do
|
14
20
|
before do
|
15
|
-
@band =
|
21
|
+
@band = Band.new
|
16
22
|
@band.extend(BandRepresenter)
|
17
23
|
@band.extend(Roar::Representer::Feature::HttpVerbs)
|
18
24
|
end
|
19
25
|
|
20
26
|
describe "HttpVerbs.get" do
|
21
27
|
it "returns instance from incoming representation" do
|
28
|
+
# let's pretend the user wants Roar class methods.
|
22
29
|
@Band = Class.new do
|
23
30
|
include Roar::Representer::JSON
|
24
31
|
include BandRepresenter
|
25
32
|
include Roar::Representer::Feature::HttpVerbs
|
33
|
+
attr_accessor :name, :label
|
26
34
|
end
|
27
35
|
@band = @Band.get("http://localhost:9999/bands/slayer", "application/json")
|
28
36
|
assert_equal "Slayer", @band.name
|
@@ -6,6 +6,7 @@ class HypermediaTest
|
|
6
6
|
describe "Hypermedia Feature" do
|
7
7
|
before do
|
8
8
|
@bookmarks = Class.new do
|
9
|
+
include AttributesContructor
|
9
10
|
include Roar::Representer::XML
|
10
11
|
include Roar::Representer::Feature::Hypermedia
|
11
12
|
|
@@ -19,6 +20,8 @@ class HypermediaTest
|
|
19
20
|
property :id
|
20
21
|
link :self do "http://bookmarks" end
|
21
22
|
link :all do "http://bookmarks/all" end
|
23
|
+
|
24
|
+
attr_accessor :id, :self, :all
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
@@ -29,7 +32,7 @@ class HypermediaTest
|
|
29
32
|
<id>1</id>
|
30
33
|
<link rel="self" href="http://bookmarks"/>
|
31
34
|
<link rel="all" href="http://bookmarks/all"/>
|
32
|
-
</bookmarks>', @bookmarks_with_links.
|
35
|
+
</bookmarks>', @bookmarks_with_links.new(:id => 1).to_xml
|
33
36
|
end
|
34
37
|
|
35
38
|
it "still works even if there are no links defined" do
|
@@ -40,7 +43,7 @@ class HypermediaTest
|
|
40
43
|
assert_xml_equal '<bookmarks>
|
41
44
|
<id>1</id>
|
42
45
|
</bookmarks>',
|
43
|
-
@bookmarks_with_links.
|
46
|
+
@bookmarks_with_links.new(:id => 1).to_xml(:links => false)
|
44
47
|
end
|
45
48
|
end
|
46
49
|
|
@@ -58,11 +61,13 @@ class HypermediaTest
|
|
58
61
|
|
59
62
|
it "sets up links even when nested" do
|
60
63
|
class Page
|
64
|
+
include AttributesContructor
|
61
65
|
include Roar::Representer::JSON
|
62
66
|
property :note, :class => Note
|
67
|
+
attr_accessor :note
|
63
68
|
end
|
64
69
|
|
65
|
-
assert_equal "{\"note\":{\"links\":[{\"rel\":\"self\",\"href\":\"http://me\"}]}}", Page.
|
70
|
+
assert_equal "{\"note\":{\"links\":[{\"rel\":\"self\",\"href\":\"http://me\"}]}}", Page.new(note: Note.new).to_json
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
@@ -78,7 +83,7 @@ class HypermediaTest
|
|
78
83
|
|
79
84
|
assert_kind_of Roar::Representer::Feature::Hypermedia::LinkCollection, doc.links
|
80
85
|
assert_equal 1, doc.links.size
|
81
|
-
assert_equal(
|
86
|
+
assert_equal(["self", "http://bookmarks"], [doc.links.first.rel, doc.links.first.href])
|
82
87
|
end
|
83
88
|
|
84
89
|
it "sets up an empty link list if no links found in the document" do
|
@@ -92,8 +97,14 @@ class HypermediaTest
|
|
92
97
|
@set = @bookmarks.new
|
93
98
|
hyper = Roar::Representer::XML::Hyperlink
|
94
99
|
|
95
|
-
@set.links = [
|
96
|
-
|
100
|
+
@set.links = [
|
101
|
+
{:rel => "self", :href => "http://self"},
|
102
|
+
{:rel => "next", :href => "http://next"}].collect do |config|
|
103
|
+
link = hyper.new
|
104
|
+
link.rel = config[:rel]
|
105
|
+
link.href = config[:href]
|
106
|
+
link
|
107
|
+
end
|
97
108
|
end
|
98
109
|
|
99
110
|
describe "#links=" do
|
@@ -160,7 +171,7 @@ class LinkCollectionTest < MiniTest::Spec
|
|
160
171
|
describe "LinkCollection" do
|
161
172
|
it "provides #update_link" do
|
162
173
|
collection = Roar::Representer::Feature::Hypermedia::LinkCollection.new
|
163
|
-
link = Roar::Representer::XML::Hyperlink.
|
174
|
+
link = Roar::Representer::XML::Hyperlink.new(rel: "self", href: "http://self")
|
164
175
|
|
165
176
|
collection.update_link(link)
|
166
177
|
assert_equal 1, collection.size
|
@@ -8,6 +8,7 @@ class JsonRepresenterTest < MiniTest::Spec
|
|
8
8
|
include Roar::Representer::JSON
|
9
9
|
property :id
|
10
10
|
property :pending
|
11
|
+
attr_accessor :id, :pending
|
11
12
|
end
|
12
13
|
|
13
14
|
|
@@ -76,8 +77,10 @@ class JsonHypermediaTest
|
|
76
77
|
describe "Hypermedia API" do
|
77
78
|
before do
|
78
79
|
@c = Class.new do
|
80
|
+
include AttributesContructor
|
79
81
|
include Roar::Representer::JSON
|
80
82
|
include Roar::Representer::Feature::Hypermedia
|
83
|
+
attr_accessor :id, :self, :next
|
81
84
|
|
82
85
|
property :id
|
83
86
|
|
@@ -96,11 +99,11 @@ class JsonHypermediaTest
|
|
96
99
|
@r = @c.from_json({:links => [{:rel => "self", :href => "http://self"}]}.to_json)
|
97
100
|
|
98
101
|
assert_equal 1, @r.links.size
|
99
|
-
assert_equal(
|
102
|
+
assert_equal(["self", "http://self"], [@r.links.first.rel, @r.links.first.href])
|
100
103
|
end
|
101
104
|
|
102
105
|
it "renders link: correctly in JSON" do
|
103
|
-
assert_equal "{\"id\":1,\"links\":[{\"rel\":\"self\",\"href\":\"http://self\"},{\"rel\":\"next\",\"href\":\"http://next/1\"}]}", @c.
|
106
|
+
assert_equal "{\"id\":1,\"links\":[{\"rel\":\"self\",\"href\":\"http://self\"},{\"rel\":\"next\",\"href\":\"http://next/1\"}]}", @c.new(:id => 1).to_json
|
104
107
|
end
|
105
108
|
end
|
106
109
|
end
|
data/test/representer_test.rb
CHANGED
@@ -17,27 +17,6 @@ class RepresenterTest < MiniTest::Spec
|
|
17
17
|
@c.collection :songs
|
18
18
|
assert_equal "songs", @c.representable_attrs.first.name
|
19
19
|
end
|
20
|
-
|
21
|
-
|
22
|
-
describe "#from_attributes" do
|
23
|
-
it "accepts a block yielding the created representer instance" do
|
24
|
-
@c.class_eval { attr_accessor :name }
|
25
|
-
|
26
|
-
assert_equal("Conan", @c.from_attributes({}) { |rep| rep.name = "Conan" }.name)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "copies known properties, only, but doesn't complain" do
|
30
|
-
@c.class_eval { property :id }
|
31
|
-
|
32
|
-
assert_equal 1, @c.from_attributes("id" => 1, "unknown" => "don't use me").id
|
33
|
-
end
|
34
|
-
|
35
|
-
it "accepts symbols and strings as property name" do
|
36
|
-
@c.class_eval { property :id }
|
37
|
-
|
38
|
-
assert_equal @c.from_attributes(:id => 1).id, @c.from_attributes("id" => 1).id
|
39
|
-
end
|
40
|
-
end
|
41
20
|
end
|
42
21
|
|
43
22
|
describe "Inheritance" do
|
@@ -48,11 +27,13 @@ class RepresenterTest < MiniTest::Spec
|
|
48
27
|
end
|
49
28
|
|
50
29
|
class Person
|
30
|
+
include AttributesContructor
|
51
31
|
include Roar::Representer::JSON
|
52
32
|
include PersonRepresentation
|
33
|
+
attr_accessor :name
|
53
34
|
end
|
54
35
|
|
55
|
-
assert_equal "{\"name\":\"Paulo\"}", Person.
|
36
|
+
assert_equal "{\"name\":\"Paulo\"}", Person.new(:name => "Paulo").to_json
|
56
37
|
end
|
57
38
|
|
58
39
|
end
|
data/test/test_helper.rb
CHANGED
@@ -8,6 +8,7 @@ require 'roar/representer'
|
|
8
8
|
require 'roar/representer/feature/hypermedia'
|
9
9
|
require 'roar/representer/feature/http_verbs'
|
10
10
|
|
11
|
+
# TODO: 2BRM.
|
11
12
|
module TestModel
|
12
13
|
def self.included(base)
|
13
14
|
base.extend ClassMethods
|
@@ -31,6 +32,15 @@ require 'roar/representer/feature/http_verbs'
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
module AttributesContructor
|
36
|
+
def initialize(attrs={})
|
37
|
+
attrs.each do |k,v|
|
38
|
+
instance_variable_set("@#{k}", v)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
34
44
|
|
35
45
|
class Item
|
36
46
|
include TestModel
|
@@ -1,16 +1,20 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class ItemRepresenter
|
4
|
+
include AttributesContructor
|
4
5
|
include Roar::Representer::XML
|
5
6
|
self.representation_wrap= :item
|
6
7
|
property :value
|
8
|
+
attr_accessor :value
|
7
9
|
end
|
8
10
|
|
9
11
|
class PositionRepresenter
|
12
|
+
include AttributesContructor
|
10
13
|
include Roar::Representer::XML
|
11
14
|
self.representation_wrap= :position
|
12
15
|
property :id
|
13
16
|
property :item, :class => ItemRepresenter
|
17
|
+
attr_accessor :id, :item
|
14
18
|
end
|
15
19
|
|
16
20
|
|
@@ -50,6 +54,7 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
50
54
|
include Roar::Representer::XML
|
51
55
|
self.representation_wrap= :order
|
52
56
|
property :id
|
57
|
+
attr_accessor :id
|
53
58
|
end
|
54
59
|
|
55
60
|
|
@@ -62,14 +67,6 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
62
67
|
@i.value = "Beer"
|
63
68
|
end
|
64
69
|
|
65
|
-
describe "#to_attributes" do
|
66
|
-
it "returns a nested attributes hash" do
|
67
|
-
@r = PositionRepresenter.from_attributes("id" => 1, "item" => @i)
|
68
|
-
assert_equal({"id" => 1, "item" => {"value" => "Beer"}}, @r.to_attributes)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
|
73
70
|
describe "#to_xml" do
|
74
71
|
it "serializes the model" do
|
75
72
|
assert_xml_equal "<order/>", @r.to_xml
|
@@ -104,10 +101,11 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
104
101
|
include Roar::Representer::XML
|
105
102
|
property :id
|
106
103
|
property :pending
|
104
|
+
attr_accessor :id, :pending
|
107
105
|
end
|
108
106
|
|
109
107
|
it "is aliased to #deserialize" do
|
110
|
-
assert_equal TestXmlRepresenter.from_xml("<order/>").
|
108
|
+
assert_equal TestXmlRepresenter.from_xml("<order/>").id, TestXmlRepresenter.deserialize("<order/>").id
|
111
109
|
end
|
112
110
|
|
113
111
|
it "accepts :except option" do
|
@@ -139,7 +137,7 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
139
137
|
|
140
138
|
describe "with a typed attribute" do
|
141
139
|
before do
|
142
|
-
@r = PositionRepresenter.
|
140
|
+
@r = PositionRepresenter.new("id" => "1")
|
143
141
|
end
|
144
142
|
|
145
143
|
it "#serialize skips empty :item" do
|
@@ -163,14 +161,16 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
163
161
|
describe "with a typed list" do
|
164
162
|
before do
|
165
163
|
@c = Class.new do
|
164
|
+
include AttributesContructor
|
166
165
|
include Roar::Representer::XML
|
167
166
|
|
168
167
|
self.representation_wrap= :order
|
169
168
|
property :id
|
170
169
|
collection :items, :class => ItemRepresenter, :from => :item
|
170
|
+
attr_accessor :id, :items
|
171
171
|
end
|
172
172
|
|
173
|
-
@r = @c.
|
173
|
+
@r = @c.new("id" => 1)
|
174
174
|
end
|
175
175
|
|
176
176
|
it "#serialize_model skips empty :item" do
|
@@ -178,7 +178,7 @@ class XMLRepresenterFunctionalTest < MiniTest::Spec
|
|
178
178
|
end
|
179
179
|
|
180
180
|
it "#serialize delegates to ItemXmlRepresenter#to_xml in list" do
|
181
|
-
@r.items = [ItemRepresenter.
|
181
|
+
@r.items = [ItemRepresenter.new("value" => "Bier")]
|
182
182
|
|
183
183
|
assert_xml_equal "<order><id>1</id><item><value>Bier</value></item></order>",
|
184
184
|
@r.to_xml
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 9
|
8
|
-
-
|
9
|
-
version: 0.9.
|
8
|
+
- 1
|
9
|
+
version: 0.9.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nick Sutterer
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-12-
|
17
|
+
date: 2011-12-28 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,30 +26,16 @@ dependencies:
|
|
26
26
|
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
segments:
|
29
|
-
-
|
30
|
-
- 12
|
31
|
-
version: "0.12"
|
32
|
-
type: :runtime
|
33
|
-
version_requirements: *id001
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: hooks
|
36
|
-
prerelease: false
|
37
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
-
none: false
|
39
|
-
requirements:
|
40
|
-
- - ~>
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
segments:
|
29
|
+
- 1
|
43
30
|
- 0
|
44
31
|
- 1
|
45
|
-
|
46
|
-
version: 0.1.4
|
32
|
+
version: 1.0.1
|
47
33
|
type: :runtime
|
48
|
-
version_requirements: *
|
34
|
+
version_requirements: *id001
|
49
35
|
- !ruby/object:Gem::Dependency
|
50
36
|
name: test_xml
|
51
37
|
prerelease: false
|
52
|
-
requirement: &
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
53
39
|
none: false
|
54
40
|
requirements:
|
55
41
|
- - ">="
|
@@ -58,11 +44,11 @@ dependencies:
|
|
58
44
|
- 0
|
59
45
|
version: "0"
|
60
46
|
type: :development
|
61
|
-
version_requirements: *
|
47
|
+
version_requirements: *id002
|
62
48
|
- !ruby/object:Gem::Dependency
|
63
49
|
name: minitest
|
64
50
|
prerelease: false
|
65
|
-
requirement: &
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
66
52
|
none: false
|
67
53
|
requirements:
|
68
54
|
- - ~>
|
@@ -73,11 +59,11 @@ dependencies:
|
|
73
59
|
- 0
|
74
60
|
version: 1.6.0
|
75
61
|
type: :development
|
76
|
-
version_requirements: *
|
62
|
+
version_requirements: *id003
|
77
63
|
- !ruby/object:Gem::Dependency
|
78
64
|
name: sinatra
|
79
65
|
prerelease: false
|
80
|
-
requirement: &
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
81
67
|
none: false
|
82
68
|
requirements:
|
83
69
|
- - ~>
|
@@ -88,7 +74,7 @@ dependencies:
|
|
88
74
|
- 6
|
89
75
|
version: 1.2.6
|
90
76
|
type: :development
|
91
|
-
version_requirements: *
|
77
|
+
version_requirements: *id004
|
92
78
|
description: Streamlines the development of RESTful, resource-oriented architectures in Ruby.
|
93
79
|
email:
|
94
80
|
- apotonick@gmail.com
|
@@ -113,7 +99,6 @@ files:
|
|
113
99
|
- lib/roar/representer.rb
|
114
100
|
- lib/roar/representer/feature/http_verbs.rb
|
115
101
|
- lib/roar/representer/feature/hypermedia.rb
|
116
|
-
- lib/roar/representer/feature/model_representing.rb
|
117
102
|
- lib/roar/representer/feature/transport.rb
|
118
103
|
- lib/roar/representer/json.rb
|
119
104
|
- lib/roar/representer/xml.rb
|
@@ -160,7 +145,6 @@ files:
|
|
160
145
|
- test/hypermedia_feature_test.rb
|
161
146
|
- test/integration_test.rb
|
162
147
|
- test/json_representer_test.rb
|
163
|
-
- test/model_representing_test.rb
|
164
148
|
- test/order_representers.rb
|
165
149
|
- test/rails/controller_methods_test.rb
|
166
150
|
- test/rails/rails_representer_methods_test.rb
|
@@ -1,80 +0,0 @@
|
|
1
|
-
module Roar
|
2
|
-
module Representer
|
3
|
-
module Feature
|
4
|
-
module ModelRepresenting
|
5
|
-
attr_accessor :represented
|
6
|
-
|
7
|
-
def self.included(base)
|
8
|
-
base.extend ClassMethods
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def for_model(represented)
|
13
|
-
# DISCUSS: split that into #for_model_attributes so it's easier overridable?
|
14
|
-
from_attributes(compute_attributes_for(represented)) { |rep| rep.represented = represented }
|
15
|
-
end
|
16
|
-
|
17
|
-
def serialize_model(represented)
|
18
|
-
for_model(represented).serialize
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
def definition_class
|
23
|
-
ModelDefinition
|
24
|
-
end
|
25
|
-
|
26
|
-
# Called in for_model.
|
27
|
-
def compute_attributes_for(represented)
|
28
|
-
{}.tap do |attributes|
|
29
|
-
self.representable_attrs.each do |definition|
|
30
|
-
next unless definition.kind_of?(ModelDefinition) # for now, really only use "our" model attributes.
|
31
|
-
definition.compute_attribute_for(represented, attributes)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
end # ClassMethods
|
38
|
-
|
39
|
-
# Properties that are mapped to a model attribute.
|
40
|
-
class ModelDefinition < ::Representable::Definition
|
41
|
-
def compute_attribute_for(represented, attributes)
|
42
|
-
value = represented.send(getter)
|
43
|
-
|
44
|
-
if typed?
|
45
|
-
value = apply(value) do |v|
|
46
|
-
sought_type.for_model(v) # applied to each typed attribute (even in collections).
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
attributes[name] = value
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
module ActiveRecordMethods
|
57
|
-
def to_nested_attributes # FIXME: extract iterating with #to_attributes.
|
58
|
-
{}.tap do |attributes|
|
59
|
-
self.class.representable_attrs.each do |definition|
|
60
|
-
next unless definition.kind_of?(ModelRepresenting::ModelDefinition)
|
61
|
-
|
62
|
-
value = public_send(definition.getter)
|
63
|
-
|
64
|
-
if definition.typed?
|
65
|
-
value = definition.apply(value) do |v|
|
66
|
-
v.to_nested_attributes # applied to each typed attribute (even in collections).
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
key = definition.name
|
71
|
-
key = "#{key}_attributes" if definition.typed?
|
72
|
-
|
73
|
-
attributes[key] = value
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'roar/representer/feature/model_representing'
|
3
|
-
|
4
|
-
class ModelRepresentingTest < MiniTest::Spec
|
5
|
-
describe "ModelRepresenting" do
|
6
|
-
class ItemRepresenter
|
7
|
-
include Roar::Representer::XML
|
8
|
-
include Roar::Representer::Feature::ModelRepresenting
|
9
|
-
self.representation_wrap= :item
|
10
|
-
property :value
|
11
|
-
end
|
12
|
-
|
13
|
-
class PositionRepresenter
|
14
|
-
include Roar::Representer::XML
|
15
|
-
include Roar::Representer::Feature::ModelRepresenting
|
16
|
-
self.representation_wrap= :position
|
17
|
-
property :id
|
18
|
-
property :item, :class => ItemRepresenter
|
19
|
-
end
|
20
|
-
|
21
|
-
class OrderRepresenter
|
22
|
-
include Roar::Representer::XML
|
23
|
-
include Roar::Representer::Feature::ModelRepresenting
|
24
|
-
self.representation_wrap= :order
|
25
|
-
property :id
|
26
|
-
collection :items, :class => ItemRepresenter
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "#definition_class" do
|
30
|
-
it "returns ModelDefinition" do
|
31
|
-
assert_equal Roar::Representer::Feature::ModelRepresenting::ModelDefinition, OrderRepresenter.send(:definition_class)
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
describe "#for_model" do
|
37
|
-
it "copies represented model attributes, nothing more" do
|
38
|
-
@o = Position.new("id" => 1, "item" => Item.new("value" => "Beer"))
|
39
|
-
@r = PositionRepresenter.for_model(@o)
|
40
|
-
assert_kind_of PositionRepresenter, @r
|
41
|
-
assert_equal 1, @r.id
|
42
|
-
|
43
|
-
@i = @r.item
|
44
|
-
assert_kind_of ItemRepresenter, @i
|
45
|
-
assert_equal "Beer", @i.value
|
46
|
-
end
|
47
|
-
|
48
|
-
it "references the model in @represented" do
|
49
|
-
@o = Position.new("id" => 1, "item" => @i = Item.new("value" => "Beer"))
|
50
|
-
|
51
|
-
@r = PositionRepresenter.for_model(@o)
|
52
|
-
assert_equal @o, @r.represented
|
53
|
-
assert_equal @i, @r.item.represented
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "#serialize_model" do
|
58
|
-
it "skips empty :item" do
|
59
|
-
@o = Position.new("id" => 1)
|
60
|
-
assert_xml_equal "<position><id>1</id></position>", PositionRepresenter.serialize_model(@o)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "skips empty [:items]" do
|
64
|
-
assert_xml_equal "<order><id>1</id></order>", OrderRepresenter.serialize_model(Order.new("id" => 1))
|
65
|
-
end
|
66
|
-
|
67
|
-
it "serializes the model" do
|
68
|
-
@o = Order.new("id" => 1, "items" => [Item.new("value" => "Beer")])
|
69
|
-
assert_xml_equal %{
|
70
|
-
<order>
|
71
|
-
<id>1</id>
|
72
|
-
<item>
|
73
|
-
<value>Beer</value>
|
74
|
-
</item>
|
75
|
-
</order>}"", OrderRepresenter.serialize_model(@o)
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
describe "#to_nested_attributes" do
|
81
|
-
it "provides a AR-compatible hash" do
|
82
|
-
@o = Order.new("id" => 1, "items" => [Item.new("value" => "Beer")])
|
83
|
-
@r = OrderRepresenter.for_model(@o)
|
84
|
-
|
85
|
-
OrderRepresenter.class_eval do
|
86
|
-
include Roar::Representer::Feature::ActiveRecordMethods
|
87
|
-
end
|
88
|
-
ItemRepresenter.class_eval do
|
89
|
-
include Roar::Representer::Feature::ActiveRecordMethods
|
90
|
-
end
|
91
|
-
assert_equal({"id" => 1, "items_attributes" => [{"value" => "Beer"}]}, @r.to_nested_attributes) # DISCUSS: overwrite #to_attributes.
|
92
|
-
end
|
93
|
-
|
94
|
-
it "doesn't include :links" do
|
95
|
-
@o = Order.new("id" => 1, "items" => [Item.new("value" => "Beer")])
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
OrderRepresenter.class_eval do
|
100
|
-
include Roar::Representer::Feature::ActiveRecordMethods
|
101
|
-
include Roar::Representer::Feature::Hypermedia
|
102
|
-
link :self do
|
103
|
-
# "bla"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
ItemRepresenter.class_eval do
|
107
|
-
include Roar::Representer::Feature::ActiveRecordMethods
|
108
|
-
include Roar::Representer::Feature::Hypermedia
|
109
|
-
link :self do
|
110
|
-
|
111
|
-
end
|
112
|
-
end
|
113
|
-
@r = OrderRepresenter.for_model(@o)
|
114
|
-
|
115
|
-
assert_equal({"id" => 1, "items_attributes" => [{"value" => "Beer"}]}, @r.to_nested_attributes) # DISCUSS: overwrite #to_attributes.
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|