roar 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -6
  3. data/CHANGES.markdown +75 -58
  4. data/CONTRIBUTING.md +31 -0
  5. data/Gemfile +12 -2
  6. data/ISSUE_TEMPLATE.md +20 -0
  7. data/LICENSE +1 -1
  8. data/README.markdown +126 -250
  9. data/Rakefile +3 -1
  10. data/examples/example.rb +0 -0
  11. data/examples/example_server.rb +0 -0
  12. data/lib/roar.rb +3 -3
  13. data/lib/roar/client.rb +8 -3
  14. data/lib/roar/decorator.rb +2 -2
  15. data/lib/roar/http_verbs.rb +0 -16
  16. data/lib/roar/hypermedia.rb +30 -56
  17. data/lib/roar/json.rb +5 -5
  18. data/lib/roar/json/collection.rb +10 -2
  19. data/lib/roar/json/hal.rb +72 -82
  20. data/lib/roar/version.rb +1 -1
  21. data/lib/roar/xml.rb +1 -1
  22. data/roar.gemspec +6 -6
  23. data/test/client_test.rb +1 -1
  24. data/test/coercion_feature_test.rb +7 -2
  25. data/test/decorator_test.rb +17 -7
  26. data/test/hal_json_test.rb +98 -106
  27. data/test/hypermedia_feature_test.rb +13 -31
  28. data/test/hypermedia_test.rb +26 -92
  29. data/test/{decorator_client_test.rb → integration/decorator_client_test.rb} +5 -4
  30. data/test/{faraday_http_transport_test.rb → integration/faraday_http_transport_test.rb} +1 -0
  31. data/test/{http_verbs_test.rb → integration/http_verbs_test.rb} +3 -2
  32. data/test/integration/json_collection_test.rb +35 -0
  33. data/test/{net_http_transport_test.rb → integration/net_http_transport_test.rb} +1 -0
  34. data/test/integration/runner.rb +2 -3
  35. data/test/integration/server.rb +6 -0
  36. data/test/json_representer_test.rb +2 -29
  37. data/test/lonely_test.rb +1 -2
  38. data/test/ssl_client_certs_test.rb +1 -1
  39. data/test/test_helper.rb +21 -3
  40. data/test/xml_representer_test.rb +6 -5
  41. metadata +22 -36
  42. data/gemfiles/Gemfile.representable-1.7 +0 -6
  43. data/gemfiles/Gemfile.representable-1.8 +0 -6
  44. data/gemfiles/Gemfile.representable-2.0 +0 -5
  45. data/gemfiles/Gemfile.representable-2.1 +0 -5
  46. data/gemfiles/Gemfile.representable-head +0 -6
  47. data/lib/roar/json/collection_json.rb +0 -208
  48. data/lib/roar/json/json_api.rb +0 -233
  49. data/test/collection_json_test.rb +0 -132
  50. data/test/hal_links_test.rb +0 -31
  51. data/test/json_api_test.rb +0 -451
  52. data/test/lib/runner.rb +0 -134
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require 'test_helper'
2
2
 
3
3
  class HypermediaTest < MiniTest::Spec
4
4
 
@@ -30,7 +30,7 @@ class HypermediaTest < MiniTest::Spec
30
30
 
31
31
  describe "#to_xml" do
32
32
  it "works when no links defined" do
33
- repr = Module.new do
33
+ decorator_class = Class.new(Roar::Decorator) do
34
34
  include Roar::XML
35
35
  include Roar::Hypermedia
36
36
 
@@ -38,22 +38,22 @@ class HypermediaTest < MiniTest::Spec
38
38
  property :title
39
39
  end
40
40
 
41
- song.extend(repr).to_xml.must_equal_xml "<song><title>Brandy Wine</title></song>"
41
+ decorator_class.new(song).to_xml.must_equal_xml "<song><title>Brandy Wine</title></song>"
42
42
  end
43
43
 
44
- let (:rpr) { Module.new do
44
+ let(:decorator_class) { Class.new(Roar::Decorator) do
45
45
  include Roar::XML
46
46
  include Roar::Hypermedia
47
47
 
48
48
  self.representation_wrap = "song"
49
49
  property :title
50
50
 
51
- link(:self) { "/songs/#{title}" }
51
+ link(:self) { "/songs/#{represented.title}" }
52
52
  link(:all) { "/songs" }
53
53
  end }
54
54
 
55
55
  it "includes links in rendered document" do
56
- song.extend(rpr).to_xml.must_equal_xml %{
56
+ decorator_class.new(song).to_xml.must_equal_xml %{
57
57
  <song>
58
58
  <title>Brandy Wine</title>
59
59
  <link rel="self" href="/songs/Brandy Wine"/>
@@ -62,23 +62,22 @@ class HypermediaTest < MiniTest::Spec
62
62
  end
63
63
 
64
64
  it "suppresses links when links: false" do
65
- song.extend(rpr).to_xml(:links => false).must_equal_xml "<song><title>Brandy Wine</title></song>"
65
+ decorator_class.new(song).to_xml(user_options: {links: false}).must_equal_xml "<song><title>Brandy Wine</title></song>"
66
66
  end
67
67
 
68
68
  it "renders nested links" do
69
- song_rpr = rpr
70
-
71
- album_rpr = Module.new do
69
+ song_decorator_class = decorator_class
70
+ album_decorator_class = Class.new(Roar::Decorator) do
72
71
  include Roar::XML
73
72
  include Roar::Hypermedia
74
73
 
75
74
  self.representation_wrap = "album"
76
- collection :songs, :extend => song_rpr
75
+ collection :songs, :extend => song_decorator_class
77
76
 
78
77
  link(:self) { "/albums/mixed" }
79
78
  end
80
79
 
81
- Album.new(:songs => [song]).extend(album_rpr).to_xml.must_equal_xml %{
80
+ album_decorator_class.new(Album.new(:songs => [song])).to_xml.must_equal_xml %{
82
81
  <album>
83
82
  <song>
84
83
  <title>Brandy Wine</title>
@@ -125,30 +124,13 @@ class HypermediaTest < MiniTest::Spec
125
124
  </bookmarks>
126
125
  })
127
126
 
128
- assert_kind_of Roar::Hypermedia::LinkCollection, doc.links
127
+ assert_kind_of Hash, doc.links
129
128
  assert_equal 1, doc.links.size
130
129
  assert_equal(["self", "http://bookmarks"], [doc.links["self"].rel, doc.links["self"].href])
131
130
  end
132
131
 
133
132
  it "sets up an empty link list if no links found in the document" do
134
- @bookmarks_with_links.new.from_xml(%{<bookmarks/>}).links.must_equal nil
135
- end
136
- end
137
- end
138
- end
139
-
140
-
141
- class LinkCollectionTest < MiniTest::Spec
142
- describe "LinkCollection" do
143
- subject {
144
- Roar::Hypermedia::LinkCollection[
145
- @self_link = link(:rel => :self), @next_link = link(:rel => :next)
146
- ]
147
- }
148
-
149
- describe "::[]" do
150
- it "keys by using rel string" do
151
- subject.values.must_equal [@self_link, @next_link]
133
+ @bookmarks_with_links.new.from_xml(%{<bookmarks/>}).links.must_equal({})
152
134
  end
153
135
  end
154
136
  end
@@ -1,52 +1,39 @@
1
1
  require 'test_helper'
2
+ require 'roar/decorator'
2
3
 
3
4
  class HypermediaTest < MiniTest::Spec
4
5
  describe "inheritance" do
5
- before do
6
- module BaseRepresenter
7
- include Roar::JSON
8
- include Roar::Hypermedia
6
+ class BaseRepresenter < Roar::Decorator
7
+ include Roar::JSON
8
+ include Roar::Hypermedia
9
9
 
10
- link(:base) { "http://base" }
11
- end
12
-
13
- module Bar
14
- include Roar::JSON
15
- include Roar::Hypermedia
16
-
17
- link(:bar) { "http://bar" }
18
- end
10
+ link(:base) { "http://base" }
11
+ end
19
12
 
20
- module Foo
21
- include Roar::JSON
22
- include Roar::Hypermedia
23
- include BaseRepresenter
24
- include Bar
13
+ class Bar < BaseRepresenter
14
+ link(:bar) { "http://bar" }
15
+ end
25
16
 
26
- link(:foo) { "http://foo" }
27
- end
17
+ class Foo < Bar
18
+ link(:foo) { "http://foo" }
28
19
  end
29
20
 
30
21
  it "inherits parent links" do
31
- foo = Object.new.extend(Foo)
32
-
33
- assert_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"bar\",\"href\":\"http://bar\"},{\"rel\":\"foo\",\"href\":\"http://foo\"}]}", foo.to_json
22
+ Foo.new(Object.new).to_json.must_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"bar\",\"href\":\"http://bar\"},{\"rel\":\"foo\",\"href\":\"http://foo\"}]}"
34
23
  end
35
24
 
36
25
  it "inherits links from all mixed-in representers" do
37
- skip
38
- Object.new.extend(BaseRepresenter).extend(Bar).to_json.must_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"bar\",\"href\":\"http://bar\"}]}"
26
+ Bar.new(Object.new).to_json.must_equal "{\"links\":[{\"rel\":\"base\",\"href\":\"http://base\"},{\"rel\":\"bar\",\"href\":\"http://bar\"}]}"
39
27
  end
40
28
  end
41
29
 
42
30
  describe "#links_array" do
43
- subject { Object.new.extend(rpr) }
31
+ subject { decorator_class.new(Object.new) }
44
32
 
45
- representer_for do
33
+ decorator_for do
46
34
  link(:self) { "//self" }
47
35
  end
48
36
 
49
-
50
37
  describe "#to_json" do
51
38
  it "renders" do
52
39
  subject.to_json.must_equal "{\"links\":[{\"rel\":\"self\",\"href\":\"//self\"}]}"
@@ -56,7 +43,7 @@ class HypermediaTest < MiniTest::Spec
56
43
  describe "#from_json" do
57
44
  it "parses" do
58
45
  subject.from_json "{\"links\":[{\"rel\":\"self\",\"href\":\"//self\"}]}"
59
- subject.links.must_equal({"self" => link("rel" => "self", "href" => "//self")})
46
+ subject.links.must_equal("self" => link("rel" => "self", "href" => "//self"))
60
47
  end
61
48
  end
62
49
 
@@ -64,7 +51,7 @@ class HypermediaTest < MiniTest::Spec
64
51
  describe "#link" do
65
52
 
66
53
  describe "with any options" do
67
- representer_for do
54
+ decorator_for do
68
55
  link(:rel => :self, :title => "Hey, @myabc") { "//self" }
69
56
  end
70
57
 
@@ -74,38 +61,39 @@ class HypermediaTest < MiniTest::Spec
74
61
  end
75
62
 
76
63
  describe "with string rel" do
77
- representer_for do
64
+ decorator_for do
78
65
  link("ns:self") { "//self" }
79
66
  end
80
67
 
81
68
  it "renders rel" do
69
+ # raise subject.inspect
82
70
  subject.to_json.must_equal "{\"links\":[{\"rel\":\"ns:self\",\"href\":\"//self\"}]}"
83
71
  end
84
72
  end
85
73
 
86
74
  describe "passing options to serialize" do
87
- representer_for do
75
+ decorator_for do
88
76
  link(:self) { |opts| "//self/#{opts[:id]}" }
89
77
  end
90
78
 
91
79
  it "receives options when rendering" do
92
- subject.to_json(:id => 1).must_equal "{\"links\":[{\"rel\":\"self\",\"href\":\"//self/1\"}]}"
80
+ subject.to_json(user_options: { id: 1 }).must_equal "{\"links\":[{\"rel\":\"self\",\"href\":\"//self/1\"}]}"
93
81
  end
94
82
 
95
83
  describe "in a composition" do
96
- representer_for do
84
+ decorator_for do
97
85
  property :entity, :extend => self
98
86
  link(:self) { |opts| "//self/#{opts[:id]}" }
99
87
  end
100
88
 
101
89
  it "propagates options" do
102
- Song.new(:entity => Song.new).extend(rpr).to_json(:id => 1).must_equal "{\"entity\":{\"links\":[{\"rel\":\"self\",\"href\":\"//self/1\"}]},\"links\":[{\"rel\":\"self\",\"href\":\"//self/1\"}]}"
90
+ decorator_class.new(Song.new(:entity => Song.new)).to_json(user_options: { id: 1 }).must_equal "{\"entity\":{\"links\":[{\"rel\":\"self\",\"href\":\"//self/1\"}]},\"links\":[{\"rel\":\"self\",\"href\":\"//self/1\"}]}"
103
91
  end
104
92
  end
105
93
  end
106
94
 
107
95
  describe "returning option hash from block" do
108
- representer_for do
96
+ decorator_for do
109
97
  link(:self) do {:href => "//self", :type => "image/jpg"} end
110
98
  link(:other) do |params|
111
99
  hash = { :href => "//other" }
@@ -119,13 +107,13 @@ class HypermediaTest < MiniTest::Spec
119
107
  end
120
108
 
121
109
  it "is rendered according to context" do
122
- subject.to_json(type: true).must_equal "{\"links\":[{\"rel\":\"self\",\"href\":\"//self\",\"type\":\"image/jpg\"},{\"rel\":\"other\",\"href\":\"//other\",\"type\":\"image/jpg\"}]}"
110
+ subject.to_json(user_options: { type: true }).must_equal "{\"links\":[{\"rel\":\"self\",\"href\":\"//self\",\"type\":\"image/jpg\"},{\"rel\":\"other\",\"href\":\"//other\",\"type\":\"image/jpg\"}]}"
123
111
  subject.to_json.must_equal "{\"links\":[{\"rel\":\"self\",\"href\":\"//self\",\"type\":\"image/jpg\"},{\"rel\":\"other\",\"href\":\"//other\"}]}"
124
112
  end
125
113
  end
126
114
 
127
115
  describe "not calling #link" do
128
- representer_for {}
116
+ decorator_for {}
129
117
 
130
118
  it "still allows rendering" do
131
119
  subject.to_json.must_equal "{}"
@@ -134,57 +122,3 @@ class HypermediaTest < MiniTest::Spec
134
122
  end
135
123
  end
136
124
  end
137
-
138
- class HyperlinkTest < MiniTest::Spec
139
- describe "Hyperlink" do
140
- subject { link(:rel => "self", "href" => "http://self", "data-whatever" => "Hey, @myabc") }
141
-
142
- it "accepts string keys in constructor" do
143
- assert_equal "Hey, @myabc", subject.send("data-whatever")
144
- end
145
-
146
- it "responds to #rel" do
147
- assert_equal "self", subject.rel
148
- end
149
-
150
- it "responds to #href" do
151
- assert_equal "http://self", subject.href
152
- end
153
-
154
- it "responds to #replace with string keys" do
155
- subject.replace("rel" => "next")
156
- assert_equal nil, subject.href
157
- assert_equal "next", subject.rel
158
- end
159
-
160
- it "responds to #each and implements Enumerable" do
161
- assert_equal ["rel:self", "href:http://self", "data-whatever:Hey, @myabc"], subject.collect { |k,v| "#{k}:#{v}" }
162
- end
163
- end
164
-
165
- describe "Config inheritance" do
166
- it "doesn't mess up with inheritable_array" do # FIXME: remove this test when uber is out.
167
- OpenStruct.new.extend( Module.new do
168
- include Roar::JSON
169
- include(Module.new do
170
- include Roar::JSON
171
- include Roar::Hypermedia
172
-
173
- property :bla
174
-
175
- link( :self) {"bo"}
176
-
177
- #puts "hey ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
178
- #puts representable_attrs.inheritable_array(:links).inspect
179
- end)
180
-
181
-
182
- #puts representable_attrs.inheritable_array(:links).inspect
183
-
184
- property :blow
185
- include Roar::Hypermedia
186
- link(:bla) { "boo" }
187
- end).to_hash.must_equal({"links"=>[{"rel"=>"self", "href"=>"bo"}, {"rel"=>"bla", "href"=>"boo"}]})
188
- end
189
- end
190
- end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'integration/runner'
2
3
  require 'roar/decorator'
3
4
  require 'roar/client'
4
5
 
@@ -6,7 +7,7 @@ class DecoratorClientTest < MiniTest::Spec
6
7
  class Crew
7
8
  attr_accessor :moniker, :company
8
9
  end
9
-
10
+
10
11
  class CrewDecorator < Roar::Decorator
11
12
  include Roar::JSON
12
13
  include Roar::Hypermedia
@@ -26,7 +27,7 @@ class DecoratorClientTest < MiniTest::Spec
26
27
  before do
27
28
  @crew = Crew.new
28
29
  @client = CrewClient.new(@crew)
29
- end
30
+ end
30
31
 
31
32
  describe 'HttpVerbs integration' do
32
33
  describe '#get' do
@@ -54,11 +55,11 @@ class DecoratorClientTest < MiniTest::Spec
54
55
  @crew.moniker = 'Silence'
55
56
  @client.to_json.must_equal %{{\"name\":\"Silence\",\"links\":[]}}
56
57
  end
57
-
58
+
58
59
  # since this is considered dangerous, we test the mutuable options.
59
60
  it "adds links: false to options" do
60
61
  @client.to_hash(options = {})
61
- options.must_equal({:links => false})
62
+ options.must_equal(user_options: {links: false})
62
63
  end
63
64
  end
64
65
  end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'integration/runner'
2
3
  require 'roar/transport/faraday'
3
4
 
4
5
  class FaradayHttpTransportTest < MiniTest::Spec
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'integration/runner'
2
3
  require 'roar/http_verbs'
3
4
  require 'roar/json'
4
5
 
@@ -80,11 +81,11 @@ class HttpVerbsTest < MiniTest::Spec
80
81
  describe "#post" do
81
82
  it "updates instance with incoming representation" do
82
83
  @band.name = "Strung Out"
83
- assert_equal nil, @band.label
84
+ assert_nil @band.label
84
85
 
85
86
  @band.post(:uri => "http://localhost:4567/bands", :as => "application/xml")
86
87
  assert_equal "STRUNG OUT", @band.name
87
- assert_equal nil, @band.label
88
+ assert_nil @band.label
88
89
  end
89
90
  end
90
91
 
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ require 'roar/json/collection'
4
+ require 'roar/client'
5
+
6
+ class JsonCollectionTest < MiniTest::Spec
7
+ class Band < OpenStruct; end
8
+
9
+ class BandRepresenter < Roar::Decorator
10
+ include Roar::JSON
11
+
12
+ property :name
13
+ property :label
14
+ end
15
+
16
+ class BandsRepresenter < Roar::Decorator
17
+ include Roar::JSON::Collection
18
+ include Roar::Client
19
+
20
+ items extend: BandRepresenter, class: Band
21
+ end
22
+
23
+ class Bands < Array
24
+ include Roar::JSON::Collection
25
+ end
26
+
27
+ let(:bands) { Bands.new }
28
+
29
+ # "[{\"name\":\"Slayer\",\"label\":\"Canadian Maple\"},{\"name\":\"Nirvana\",\"label\":\"Sub Pop\"}])"
30
+ it 'fetches lonely collection of existing bands' do
31
+ BandsRepresenter.new(bands).get(uri: 'http://localhost:4567/bands', as: 'application/json')
32
+ bands.size.must_equal(2)
33
+ bands[0].name.must_equal('Slayer')
34
+ end
35
+ end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'integration/runner'
2
3
  require 'roar/transport/net_http'
3
4
 
4
5
  class NetHTTPTransportTest < MiniTest::Spec
@@ -1,6 +1,5 @@
1
1
  require "integration/band_representer"
2
- # require 'sinatra/runner' # TODO: merge that into sinatra-contrib.
3
- require 'lib/runner'
2
+ require 'sinatra/runner'
4
3
 
5
4
  class ServerRunner < Sinatra::Runner
6
5
  def app_file
@@ -46,4 +45,4 @@ rescue Exception => e
46
45
  ssl_runner.kill
47
46
 
48
47
  raise e
49
- end
48
+ end
@@ -55,6 +55,12 @@ post "/bands" do
55
55
  status 201
56
56
  end
57
57
 
58
+ get '/bands' do
59
+ [OpenStruct.new(:name => "Slayer", :label => "Canadian Maple"),
60
+ OpenStruct.new(:name => "Nirvana", :label => "Sub Pop")]
61
+ .extend(Integration::BandRepresenter.for_collection).to_json
62
+ end
63
+
58
64
  put "/bands/strungout" do
59
65
  # DISCUSS: as long as we don't agree on what to return in PUT/PATCH, let's return an updated document.
60
66
  body consume_band.to_json
@@ -61,7 +61,7 @@ class JsonRepresenterTest < MiniTest::Spec
61
61
 
62
62
  it "accepts :include and :exclude" do
63
63
  @order.from_json('{"id":1}', :exclude => [:id])
64
- assert_equal nil, @order.id
64
+ assert_nil @order.id
65
65
  end
66
66
  end
67
67
 
@@ -74,32 +74,6 @@ class JsonRepresenterTest < MiniTest::Spec
74
74
  end
75
75
  end
76
76
 
77
- # test the generic roar+json HyperlinkRepresenter
78
- class JsonHyperlinkRepresenterTest
79
- describe "API" do
80
- before do
81
- @link = Roar::Hypermedia::Hyperlink.new.extend(Roar::JSON::HyperlinkRepresenter).from_json(
82
- '{"rel":"self", "href":"http://roar.apotomo.de", "media":"web"}')
83
- end
84
-
85
- it "responds to #rel" do
86
- assert_equal "self", @link.rel
87
- end
88
-
89
- it "responds to #href" do
90
- assert_equal "http://roar.apotomo.de", @link.href
91
- end
92
-
93
- it "responds to #media" do
94
- assert_equal "web", @link.media
95
- end
96
-
97
- it "responds to #to_json" do
98
- assert_equal "{\"rel\":\"self\",\"href\":\"http://roar.apotomo.de\",\"media\":\"web\"}", @link.to_json
99
- end
100
- end
101
- end
102
-
103
77
  class JsonHypermediaTest
104
78
  describe "Hypermedia API" do
105
79
  before do
@@ -119,7 +93,7 @@ class JsonHypermediaTest
119
93
  end
120
94
 
121
95
  it "responds to #links" do
122
- @r.links.must_equal nil
96
+ @r.links.must_equal({})
123
97
  end
124
98
 
125
99
  it "extracts links from JSON" do
@@ -146,4 +120,3 @@ class JsonHypermediaTest
146
120
 
147
121
  end
148
122
  end
149
-