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