roar 1.0.4 → 1.1.0

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.
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
-