roar 1.0.2 → 1.1.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.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +20 -0
  3. data/.travis.yml +16 -11
  4. data/CHANGES.markdown +86 -57
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +7 -4
  7. data/LICENSE +1 -1
  8. data/README.markdown +133 -255
  9. data/Rakefile +3 -1
  10. data/examples/example.rb +0 -0
  11. data/examples/example_server.rb +0 -0
  12. data/lib/roar/client.rb +8 -3
  13. data/lib/roar/decorator.rb +2 -2
  14. data/lib/roar/http_verbs.rb +0 -16
  15. data/lib/roar/hypermedia.rb +30 -56
  16. data/lib/roar/json/collection.rb +10 -2
  17. data/lib/roar/json/hal.rb +74 -83
  18. data/lib/roar/json.rb +5 -5
  19. data/lib/roar/version.rb +1 -1
  20. data/lib/roar/xml.rb +1 -1
  21. data/lib/roar.rb +3 -3
  22. data/roar.gemspec +7 -5
  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 +101 -94
  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 +21 -37
  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
data/Rakefile CHANGED
@@ -7,6 +7,8 @@ task :default => [:test]
7
7
 
8
8
  Rake::TestTask.new(:test) do |test|
9
9
  test.libs << 'test'
10
- test.test_files = FileList['test/*_test.rb']
10
+ test.test_files = FileList.new('test/**/*_test.rb') do |fl|
11
+ fl.exclude('test/integration/**') if RUBY_VERSION < '2.2.2'
12
+ end
11
13
  test.verbose = true
12
14
  end
data/examples/example.rb CHANGED
File without changes
File without changes
data/lib/roar/client.rb CHANGED
@@ -2,7 +2,7 @@ require "roar/http_verbs"
2
2
 
3
3
  module Roar
4
4
 
5
- # Mix in HttpVerbs.
5
+ # Mix in HttpVerbs.
6
6
  module Client
7
7
  include HttpVerbs
8
8
 
@@ -28,12 +28,17 @@ module Roar
28
28
  end
29
29
 
30
30
  def to_hash(options={})
31
- options[:links] ||= false
31
+ # options[:links] ||= false
32
+ options[:user_options] ||= {}
33
+ options[:user_options][:links] ||= false
34
+
32
35
  super(options)
33
36
  end
34
37
 
35
38
  def to_xml(options={}) # sorry, but i'm not even sure if anyone uses this module.
36
- options[:links] ||= false
39
+ options[:user_options] ||= {}
40
+ options[:user_options][:links] ||= false
41
+
37
42
  super(options)
38
43
  end
39
44
  end
@@ -4,8 +4,8 @@ require 'representable/decorator'
4
4
  class Roar::Decorator < Representable::Decorator
5
5
  module HypermediaConsumer
6
6
  def links=(arr)
7
- links = super
8
- represented.instance_variable_set :@links, links
7
+ super
8
+ represented.instance_variable_set :@links, self.links
9
9
  end
10
10
  end
11
11
  end
@@ -68,21 +68,5 @@ module Roar
68
68
  def http
69
69
  transport_engine.new
70
70
  end
71
-
72
- def handle_deprecated_args(body, *args) # TODO: remove in 1.0.
73
- options = args.first
74
-
75
- if args.size > 1
76
- warn %{DEPRECATION WARNING: #get, #post, #put, #delete and #patch no longer accept positional arguments. Please call them as follows:
77
- get(uri: "http://localhost/songs", as: "application/json")
78
- post(uri: "http://localhost/songs", as: "application/json")
79
- Thank you and have a beautiful day.}
80
- options = {:uri => args[0], :as => args[1]} if args.size == 2
81
- options = {:uri => args[0], :as => args[2]}
82
- end
83
-
84
- options[:body] = body
85
- options
86
- end
87
71
  end
88
72
  end
@@ -33,33 +33,26 @@ module Roar
33
33
  #
34
34
  # model.to_json(:id => 1)
35
35
  module Hypermedia
36
- # links= [Hyperlink, Hyperlink] is where parsing happens.
37
36
  def self.included(base)
38
37
  base.extend ClassMethods
39
38
  end
40
39
 
41
- def links=(arr) # called when assigning parsed links.
42
- @links = LinkCollection[*arr]
40
+ # public API: #links (only helpful in clients, though).
41
+ attr_writer :links # this is called in parsing when Hyperlinks are deserialized.
42
+ def links # this is _not_ called by rendering as we go via ::links_config.
43
+ tuples = (@links||[]).collect { |link| [link.rel, link] }
44
+ # tuples.to_h
45
+ ::Hash[tuples] # TODO: tuples.to_h when dropping < 2.1.
43
46
  end
44
47
 
45
- attr_reader :links # this is only useful after parsing.
46
-
47
-
48
- module LinkConfigsMethod
49
- def link_configs # we could store the ::link configs in links Definition.
50
- representable_attrs[:links] ||= Representable::Inheritable::Array.new
51
- end
52
- end
53
-
54
- include LinkConfigsMethod
55
-
56
48
  private
57
49
  # Create hypermedia links for this instance by invoking their blocks.
58
50
  # This is called in links: getter: {}.
59
51
  def prepare_links!(options)
60
- return [] if options[:links] == false
52
+ return [] if (options[:user_options] || {})[:links] == false
61
53
 
62
- LinkCollection[*compile_links_for(link_configs, options)]
54
+ link_configs = representable_attrs["links"].link_configs
55
+ compile_links_for(link_configs, options)
63
56
  end
64
57
 
65
58
  def compile_links_for(configs, *args)
@@ -72,41 +65,12 @@ module Roar
72
65
  end
73
66
 
74
67
  def prepare_link_for(href, options)
75
- options = options.merge(href.is_a?(::Hash) ? href : {:href => href})
68
+ options = options.merge(href.is_a?(::Hash) ? href : {href: href})
76
69
  Hyperlink.new(options)
77
70
  end
78
71
 
79
- def run_link_block(block, *args)
80
- instance_exec(*args, &block)
81
- end
82
-
83
-
84
- # LinkCollection keeps an array of Hyperlinks to be rendered (setup in #prepare_links!)
85
- # or parsed (array is passed to #links= which transforms it into a LinkCollection).
86
- # It is implemented as a hash and keys links by their rel value.
87
- #
88
- # {"self" => <Hyperlink ..>, ..}
89
- class LinkCollection < ::Hash
90
- # The only way to create is LinkCollection[<Hyperlink>, <Hyperlink>]
91
- def self.[](*arr)
92
- super(arr.collect { |link| [link.rel, link] })
93
- end
94
-
95
- def [](rel)
96
- super(rel.to_s)
97
- end
98
-
99
- # Iterating links. Block parameters: |link| or |rel, link|.
100
- # This is used Hash::HashBinding#serialize.
101
- def each(&block)
102
- return values.each(&block) if block.arity == 1
103
- super(&block)
104
- end
105
-
106
- def collect(&block) # TODO: remove me when we drop representable 2.0.x support!
107
- return values.collect(&block) if block.arity == 1
108
- super(&block)
109
- end
72
+ def run_link_block(block, options)
73
+ instance_exec(options[:user_options], &block)
110
74
  end
111
75
 
112
76
 
@@ -122,23 +86,34 @@ module Roar
122
86
  # The block is executed in instance context, so you may call properties or other accessors.
123
87
  # Note that you're free to put decider logic into #link blocks, too.
124
88
  def link(options, &block)
125
- create_links_definition! # this assures the links are rendered at the right position.
89
+ heritage.record(:link, options, &block)
90
+
91
+ links_dfn = create_links_definition! # this assures the links are rendered at the right position.
126
92
 
127
93
  options = {:rel => options} unless options.is_a?(::Hash)
128
- link_configs << [options, block]
129
- end
130
94
 
131
- include LinkConfigsMethod
95
+ links_dfn.link_configs << [options, block]
96
+ end
132
97
 
133
98
  private
134
99
  # Add a :links Definition to the representable_attrs so they get rendered/parsed.
135
100
  def create_links_definition!
136
- return if representable_attrs.get(:links) # only create it once.
101
+ dfn = definitions["links"] and return dfn # only create it once.
137
102
 
138
103
  options = links_definition_options
139
- options.merge!(:getter => lambda { |opts| prepare_links!(opts) })
104
+ options.merge!(getter: ->(opts) { prepare_links!(opts) })
105
+
106
+ dfn = build_definition(:links, options)
107
+
108
+
109
+ dfn.extend(DefinitionOptions)
110
+ dfn
111
+ end
112
+ end
140
113
 
141
- representable_attrs.add(:links, options)
114
+ module DefinitionOptions
115
+ def link_configs
116
+ @link_configs ||= []
142
117
  end
143
118
  end
144
119
 
@@ -172,7 +147,6 @@ module Roar
172
147
  attrs.inject({}) { |hsh, kv| hsh[kv.first.to_s] = kv.last; hsh }.tap do |hsh|
173
148
  hsh["rel"] = hsh["rel"].to_s if hsh["rel"]
174
149
  end
175
- # raise "Hyperlink without rel doesn't work!" unless @attrs["rel"]
176
150
  end
177
151
  end
178
152
  end
@@ -1,3 +1,11 @@
1
- require "representable/json/collection"
1
+ require 'roar/json'
2
2
 
3
- Roar::JSON::Collection = Representable::JSON::Collection
3
+ module Roar::JSON
4
+ module Collection
5
+ include Roar::JSON
6
+
7
+ def self.included(base)
8
+ base.send :include, Representable::Hash::Collection
9
+ end
10
+ end
11
+ end
data/lib/roar/json/hal.rb CHANGED
@@ -1,4 +1,6 @@
1
- require 'roar/json'
1
+ require "roar/json"
2
+ require "representable/json/collection"
3
+ require "representable/json/hash"
2
4
 
3
5
  module Roar
4
6
  module JSON
@@ -46,8 +48,8 @@ module Roar
46
48
  base.class_eval do
47
49
  include Roar::JSON
48
50
  include Links # overwrites #links_definition_options.
49
- extend ClassMethods # overwrites #links_definition_options, again.
50
51
  include Resources
52
+ include LinksReader # gives us Decorator#links => {self=>< >}
51
53
  end
52
54
  end
53
55
 
@@ -56,8 +58,9 @@ module Roar
56
58
  super.tap do |hash|
57
59
  embedded = {}
58
60
  representable_attrs.find_all do |dfn|
59
- next unless dfn[:embedded] and fragment = hash.delete(dfn.name)
60
- embedded[dfn.name] = fragment
61
+ name = dfn[:as] ? dfn[:as].(nil) : dfn.name # DISCUSS: should we simplify that in Representable?
62
+ next unless dfn[:embedded] and fragment = hash.delete(name)
63
+ embedded[name] = fragment
61
64
  end
62
65
 
63
66
  hash["_embedded"] = embedded if embedded.any?
@@ -71,38 +74,7 @@ module Roar
71
74
  end
72
75
  end
73
76
 
74
- module ClassMethods
75
- def links_definition_options
76
- super.merge(:as => :_links)
77
- end
78
- end
79
77
 
80
- class LinkCollection < Hypermedia::LinkCollection
81
- def initialize(array_rels, *args)
82
- super(*args)
83
- @array_rels = array_rels.map(&:to_s)
84
- end
85
-
86
- def is_array?(rel)
87
- @array_rels.include?(rel.to_s)
88
- end
89
- end
90
-
91
- # Including this module in your representer will render and parse your embedded hyperlinks
92
- # following the HAL specification: http://stateless.co/hal_specification.html
93
- #
94
- # module SongRepresenter
95
- # include Roar::JSON
96
- # include Roar::JSON::HAL::Links
97
- #
98
- # link :self { "http://self" }
99
- # end
100
- #
101
- # Renders to
102
- #
103
- # {"links":{"self":{"href":"http://self"}}}
104
- #
105
- # Note that the HAL::Links module alone doesn't prepend an underscore to +links+. Use the JSON::HAL module for that.
106
78
  module Links
107
79
  def self.included(base)
108
80
  base.extend ClassMethods # ::links_definition_options
@@ -111,83 +83,84 @@ module Roar
111
83
  end
112
84
 
113
85
  module InstanceMethods
86
+ def _links
87
+ links
88
+ end
89
+
114
90
  private
115
91
  def prepare_link_for(href, options)
116
- return super(href, options) unless options[:array] # TODO: remove :array and use special instan
92
+ return super(href, options) unless options[:array] # returns Hyperlink.
117
93
 
118
- list = href.collect { |opts| Hypermedia::Hyperlink.new(opts.merge!(:rel => options[:rel])) }
119
- LinkArray.new(list, options[:rel])
120
- end
121
-
122
- # TODO: move to LinksDefinition.
123
- def link_array_rels
124
- link_configs.collect { |cfg| cfg.first[:array] ? cfg.first[:rel] : nil }.compact
94
+ ArrayLink.new(options[:rel], href.collect { |opts| Hypermedia::Hyperlink.new(opts) })
125
95
  end
126
96
  end
127
97
 
128
98
 
129
- require 'representable/json/hash'
130
- module LinkCollectionRepresenter
131
- include Representable::JSON::Hash
132
-
133
- values :extend => lambda { |item, *|
134
- item.is_a?(Array) ? LinkArrayRepresenter : Roar::JSON::HyperlinkRepresenter },
135
- :instance => lambda { |fragment, *| fragment.is_a?(LinkArray) ? fragment : Roar::Hypermedia::Hyperlink.new
136
- }
99
+ class SingleLink
100
+ class Representer < Representable::Decorator
101
+ include Representable::JSON::Hash
137
102
 
138
- def to_hash(options)
139
- super.tap do |hsh| # TODO: cool: super(:exclude => [:rel]).
140
- hsh.each { |k,v| v.delete("rel") }
103
+ def to_hash(*)
104
+ hash = super
105
+ {hash.delete("rel").to_s => hash}
141
106
  end
142
107
  end
143
-
144
-
145
- def from_hash(hash, *args)
146
- hash.each { |k,v| hash[k] = LinkArray.new(v, k) if is_array?(k) }
147
-
148
- hsh = super(hash) # this is where :class and :extend do the work.
149
-
150
- hsh.each { |k, v| v.merge!(:rel => k) }
151
- hsh.values # links= expects [Hyperlink, Hyperlink]
152
- end
153
108
  end
154
109
 
155
- # DISCUSS: we can probably get rid of this asset.
156
- class LinkArray < Array
157
- def initialize(elems, rel)
158
- super(elems)
110
+ class ArrayLink < Array
111
+ def initialize(rel, links)
159
112
  @rel = rel
113
+ super(links)
160
114
  end
161
-
162
115
  attr_reader :rel
163
116
 
164
- def merge!(attrs)
165
- each { |lnk| lnk.merge!(attrs) }
117
+
118
+ # [Hyperlink, Hyperlink]
119
+ class Representer < Representable::Decorator
120
+ include Representable::JSON::Collection
121
+
122
+ items extend: SingleLink::Representer,
123
+ class: Roar::Hypermedia::Hyperlink
124
+
125
+ def to_hash(*)
126
+ links = super.flat_map(&:values) # [{"self"=>{"href": ..}}, ..]
127
+
128
+ { represented.rel.to_s => links } # {"self"=>[{"lang"=>"en", "href"=>"http://en.hit"}, {"lang"=>"de", "href"=>"http://de.hit"}]}
129
+ end
166
130
  end
167
131
  end
168
132
 
169
- require 'representable/json/collection'
170
- module LinkArrayRepresenter
133
+
134
+ # Represents all links for "_links": [Hyperlink, [Hyperlink, Hyperlink]]
135
+ class Representer < Representable::Decorator # links could be a simple collection property.
171
136
  include Representable::JSON::Collection
172
137
 
173
- items :extend => Roar::JSON::HyperlinkRepresenter,
174
- :class => Roar::Hypermedia::Hyperlink
138
+ # render: decorates represented.links with ArrayLink::R or SingleLink::R and calls #to_hash.
139
+ # parse: instantiate either Array or Hypermedia instance, decorate respectively, call #from_hash.
140
+ items decorator: ->(options) { options[:input].is_a?(Array) ? ArrayLink::Representer : SingleLink::Representer },
141
+ class: ->(options) { options[:input].is_a?(Array) ? Array : Hypermedia::Hyperlink }
142
+
143
+ def to_hash(options)
144
+ super.inject({}) { |links, hash| links.merge!(hash) } # [{ rel=>{}, rel=>[{}, {}] }]
145
+ end
175
146
 
176
- def to_hash(*)
177
- super.tap do |ary|
178
- ary.each { |lnk| rel = lnk.delete("rel") }
147
+ def from_hash(hash, *args)
148
+ collection = hash.collect do |rel, value| # "self" => [{"href": "//"}, ] or "self" => {"href": "//"}
149
+ value.is_a?(Array) ? value.collect { |link| link.merge("rel"=>rel) } : value.merge("rel"=>rel)
179
150
  end
151
+
152
+ super(collection) # [{rel=>self, href=>//}, ..] or {rel=>self, href=>//}
180
153
  end
181
154
  end
182
155
 
183
156
 
184
157
  module ClassMethods
185
158
  def links_definition_options
186
- # property :links_array,
187
159
  {
188
- :as => :links,
189
- :extend => HAL::Links::LinkCollectionRepresenter,
190
- :instance => lambda { |*| LinkCollection.new(link_array_rels) }, # defined in InstanceMethods as this is executed in represented context.
160
+ # collection: false,
161
+ :as => :_links,
162
+ decorator: Links::Representer,
163
+ instance: ->(*) { Array.new }, # defined in InstanceMethods as this is executed in represented context.
191
164
  :exec_context => :decorator,
192
165
  }
193
166
  end
@@ -199,7 +172,7 @@ module Roar
199
172
  # {:lang => "de", :href => "http://de.hit"}]
200
173
  # end
201
174
  def links(options, &block)
202
- options = {:rel => options} if options.is_a?(Symbol)
175
+ options = {:rel => options} if options.is_a?(Symbol) || options.is_a?(String)
203
176
  options[:array] = true
204
177
  link(options, &block)
205
178
  end
@@ -217,6 +190,24 @@ module Roar
217
190
  end
218
191
  end
219
192
  end
193
+
194
+ # This is only helpful in client mode. It shouldn't be used per default.
195
+ module LinksReader
196
+ def links
197
+ return unless @links
198
+ tuples = @links.collect do |link|
199
+ if link.is_a?(Array)
200
+ next unless link.any?
201
+ [link.first.rel, link]
202
+ else
203
+ [link.rel, link]
204
+ end
205
+ end.compact
206
+
207
+ # tuples.to_h
208
+ ::Hash[tuples] # TODO: tuples.to_h when dropping < 2.1.
209
+ end
210
+ end
220
211
  end
221
212
  end
222
213
  end
data/lib/roar/json.rb CHANGED
@@ -37,10 +37,10 @@ module Roar
37
37
  def links_definition_options
38
38
  # FIXME: this doesn't belong into the generic JSON representer.
39
39
  {
40
- :collection => true,
41
- :class => Hypermedia::Hyperlink,
42
- :extend => HyperlinkRepresenter,
43
- :exec_context => :decorator,
40
+ class: Hypermedia::Hyperlink,
41
+ decorator: HyperlinkDecorator,
42
+ collection: true,
43
+ exec_context: :decorator
44
44
  }
45
45
  end
46
46
  end
@@ -48,7 +48,7 @@ module Roar
48
48
 
49
49
  require "representable/json/hash"
50
50
  # Represents a hyperlink in standard roar+json hash representation.
51
- module HyperlinkRepresenter
51
+ class HyperlinkDecorator < Representable::Decorator
52
52
  include Representable::JSON::Hash
53
53
  end
54
54
  end
data/lib/roar/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Roar
2
- VERSION = "1.0.2"
2
+ VERSION = "1.1.1"
3
3
  end
data/lib/roar/xml.rb CHANGED
@@ -35,10 +35,10 @@ module Roar
35
35
  # FIXME: this doesn't belong into the generic XML representer.
36
36
  {
37
37
  :as => :link,
38
- :collection => true,
39
38
  :class => Hypermedia::Hyperlink,
40
39
  :extend => XML::HyperlinkRepresenter,
41
40
  :exec_context => :decorator,
41
+ collection: true
42
42
  } # TODO: merge with JSON.
43
43
  end
44
44
  end
data/lib/roar.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'roar/version'
2
+
2
3
  module Roar
3
- def self.root
4
- File.expand_path '../..', __FILE__
5
- end
6
4
  end
5
+
6
+ require "roar/decorator"
data/roar.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Nick Sutterer"]
9
9
  s.email = ["apotonick@gmail.com"]
10
- s.homepage = "http://rubygems.org/gems/roar"
10
+ s.homepage = "http://trailblazer.to/gems/roar"
11
11
  s.summary = %q{Parse and render REST API documents using representers.}
12
12
  s.description = %q{Object-oriented representers help you defining nested REST API documents which can then be rendered and parsed using one and the same concept.}
13
13
  s.license = 'MIT'
@@ -17,14 +17,16 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
- s.add_runtime_dependency "representable", ">= 2.0.1", "<= 3.0.0"
20
+ s.required_ruby_version = '>= 1.9.3'
21
21
 
22
- s.add_development_dependency "rake", ">= 0.10.1"
22
+ s.add_runtime_dependency "representable", "~> 3.0"
23
+
24
+ s.add_development_dependency "rake"
23
25
  s.add_development_dependency "test_xml", "0.1.6"
24
- s.add_development_dependency "minitest", ">= 5.4.2"
26
+ s.add_development_dependency 'minitest', '>= 5.10'
25
27
  s.add_development_dependency "sinatra"
26
28
  s.add_development_dependency "sinatra-contrib"
27
29
  s.add_development_dependency "virtus", ">= 1.0.0"
28
30
  s.add_development_dependency "faraday"
29
- s.add_development_dependency "json"
31
+ s.add_development_dependency "multi_json"
30
32
  end
data/test/client_test.rb CHANGED
@@ -30,7 +30,7 @@ class ClientTest < MiniTest::Spec
30
30
  # since this is considered dangerous, we test the mutuable options.
31
31
  it "adds links: false to options" do
32
32
  song.to_hash(options = {})
33
- options.must_equal({:links => false})
33
+ options.must_equal(user_options: {links: false})
34
34
  end
35
35
  end
36
36
  end
@@ -1,14 +1,17 @@
1
1
  require 'test_helper'
2
2
  require 'roar/coercion'
3
+ require 'roar/decorator'
3
4
 
4
5
  class CoercionFeatureTest < MiniTest::Spec
5
6
  describe "Coercion" do
6
- class ImmigrantSong
7
+ class SongDecorator < Roar::Decorator
7
8
  include Roar::JSON
8
9
  include Roar::Coercion
9
10
 
10
11
  property :composed_at, :type => DateTime, :default => "May 12th, 2012"
12
+ end
11
13
 
14
+ class ImmigrantSong
12
15
  attr_accessor :composed_at
13
16
  def composed_at=(v) # in ruby 2.2, #label= is not there, all at sudden. what *is* that?
14
17
  @composed_at = v
@@ -16,7 +19,9 @@ class CoercionFeatureTest < MiniTest::Spec
16
19
  end
17
20
 
18
21
  it "coerces into the provided type" do
19
- song = ImmigrantSong.new.from_json("{\"composed_at\":\"November 18th, 1983\"}")
22
+ song = ImmigrantSong.new
23
+ decorator = SongDecorator.new(song)
24
+ decorator.from_json("{\"composed_at\":\"November 18th, 1983\"}")
20
25
  assert_equal DateTime.parse("Fri, 18 Nov 1983 00:00:00 +0000"), song.composed_at
21
26
  end
22
27
  end
@@ -27,11 +27,15 @@ class DecoratorTest < MiniTest::Spec
27
27
  describe "JSON" do
28
28
  let (:decorator_class) { rpr_mod = rpr
29
29
  Class.new(Roar::Decorator) do
30
+ include Roar::JSON
31
+ include Roar::Hypermedia
32
+
30
33
  include rpr_mod
31
34
  end }
32
35
  let (:decorator) { decorator_class.new(model) }
33
36
 
34
- it "rendering links works" do
37
+ it "xxxrendering links works" do
38
+ pp decorator.send(:representable_attrs)
35
39
  decorator.to_hash.must_equal({"links"=>[{"rel"=>"self", "href"=>"http://self"}]})
36
40
  end
37
41
 
@@ -42,7 +46,7 @@ class DecoratorTest < MiniTest::Spec
42
46
 
43
47
  it "does not set links on represented" do
44
48
  decorator_class.new(model_with_links).from_hash("links"=>[{:rel=>:self, :href=>"http://self"}])
45
- model_with_links.links.must_equal nil
49
+ model_with_links.links.must_be_nil
46
50
  end
47
51
 
48
52
  class ConsumingDecorator < Roar::Decorator
@@ -63,10 +67,10 @@ class DecoratorTest < MiniTest::Spec
63
67
  decorator.from_hash("links"=>[{:rel=>:self, :href=>"http://percolator"}])
64
68
 
65
69
  # links are always set on decorator instance.
66
- decorator .links[:self].must_equal(link(:rel=>:self, :href=>"http://percolator"))
70
+ decorator.links["self"].must_equal(link(:rel=>:self, :href=>"http://percolator"))
67
71
 
68
72
  # and propagated to represented with HypermediaConsumer.
69
- model_with_links.links[:self].must_equal(link(:rel=>:self, :href=>"http://percolator"))
73
+ model_with_links.links["self"].must_equal(link(:rel=>:self, :href=>"http://percolator"))
70
74
  end
71
75
  end
72
76
  end
@@ -78,6 +82,8 @@ class DecoratorTest < MiniTest::Spec
78
82
  end
79
83
  let (:decorator_class) { rpr_mod = rpr
80
84
  Class.new(Roar::Decorator) do
85
+ include Roar::XML
86
+ include Roar::Hypermedia
81
87
  include rpr_mod
82
88
  self.representation_wrap = :song
83
89
  end
@@ -97,10 +103,13 @@ class DecoratorTest < MiniTest::Spec
97
103
 
98
104
  describe "JSON::HAL" do
99
105
  representer_for([Roar::JSON::HAL]) do
106
+ # feature Roar::JSON::HAL
100
107
  link(:self) { "http://self" }
101
108
  end
102
109
  let (:decorator_class) { rpr_mod = rpr
103
110
  Class.new(Roar::Decorator) do
111
+ include Roar::JSON::HAL
112
+
104
113
  include rpr_mod
105
114
  end
106
115
  }
@@ -116,15 +125,16 @@ class DecoratorTest < MiniTest::Spec
116
125
  end
117
126
 
118
127
  describe "Decorator::HypermediaClient" do
119
- let (:decorator) { rpr_mod = rpr
128
+ let (:decorator_class) { rpr_mod = rpr
120
129
  Class.new(Roar::Decorator) do
130
+ include Roar::JSON::HAL
121
131
  include rpr_mod
122
132
  include Roar::Decorator::HypermediaConsumer
123
133
  end }
124
134
 
125
135
  it "propagates links to represented" do
126
- decorator.new(model_with_links).from_hash("_links"=>{"self"=>{:href=>"http://self"}})
127
- model_with_links.links[:self].must_equal(link(:rel=>"self", :href=>"http://self"))
136
+ decorator_class.new(model_with_links).from_hash("_links"=>{"self"=>{:href=>"http://self"}})
137
+ model_with_links.links["self"].must_equal(link(:rel=>"self", :href=>"http://self"))
128
138
  end
129
139
  end
130
140
  end