roar 1.0.2 → 1.1.1

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