roar 0.12.9 → 1.0.0.beta1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +8 -10
  4. data/CHANGES.markdown +24 -2
  5. data/Gemfile +5 -2
  6. data/README.markdown +132 -28
  7. data/TODO.markdown +9 -7
  8. data/examples/example.rb +2 -0
  9. data/examples/example_server.rb +19 -3
  10. data/gemfiles/Gemfile.representable-2.0 +5 -0
  11. data/gemfiles/Gemfile.representable-2.1 +5 -0
  12. data/lib/roar.rb +1 -1
  13. data/lib/roar/client.rb +38 -0
  14. data/lib/roar/{representer/feature/coercion.rb → coercion.rb} +2 -1
  15. data/lib/roar/decorator.rb +3 -11
  16. data/lib/roar/http_verbs.rb +88 -0
  17. data/lib/roar/hypermedia.rb +174 -0
  18. data/lib/roar/json.rb +55 -0
  19. data/lib/roar/json/collection.rb +3 -0
  20. data/lib/roar/{representer/json → json}/collection_json.rb +20 -20
  21. data/lib/roar/{representer/json → json}/hal.rb +33 -31
  22. data/lib/roar/json/hash.rb +3 -0
  23. data/lib/roar/json/json_api.rb +208 -0
  24. data/lib/roar/representer.rb +3 -36
  25. data/lib/roar/transport/faraday.rb +49 -0
  26. data/lib/roar/transport/net_http.rb +57 -0
  27. data/lib/roar/transport/net_http/request.rb +72 -0
  28. data/lib/roar/version.rb +1 -1
  29. data/lib/roar/xml.rb +54 -0
  30. data/roar.gemspec +5 -4
  31. data/test/client_test.rb +3 -3
  32. data/test/coercion_feature_test.rb +6 -3
  33. data/test/collection_json_test.rb +8 -10
  34. data/test/decorator_test.rb +27 -15
  35. data/test/faraday_http_transport_test.rb +13 -15
  36. data/test/hal_json_test.rb +16 -16
  37. data/test/hal_links_test.rb +3 -3
  38. data/test/http_verbs_test.rb +17 -22
  39. data/test/hypermedia_feature_test.rb +23 -45
  40. data/test/hypermedia_test.rb +11 -23
  41. data/test/integration/band_representer.rb +2 -2
  42. data/test/integration/runner.rb +4 -3
  43. data/test/integration/server.rb +13 -2
  44. data/test/integration/ssl_server.rb +1 -1
  45. data/test/json_api_test.rb +336 -0
  46. data/test/json_representer_test.rb +16 -12
  47. data/test/lib/runner.rb +134 -0
  48. data/test/lonely_test.rb +9 -0
  49. data/test/net_http_transport_test.rb +4 -4
  50. data/test/representer_test.rb +2 -2
  51. data/test/{lib/roar/representer/transport/net_http/request_test.rb → ssl_client_certs_test.rb} +43 -5
  52. data/test/test_helper.rb +12 -5
  53. data/test/xml_representer_test.rb +26 -166
  54. metadata +49 -29
  55. data/gemfiles/Gemfile.representable-1.7 +0 -6
  56. data/gemfiles/Gemfile.representable-1.8 +0 -6
  57. data/lib/roar/representer/feature/client.rb +0 -39
  58. data/lib/roar/representer/feature/http_verbs.rb +0 -95
  59. data/lib/roar/representer/feature/hypermedia.rb +0 -175
  60. data/lib/roar/representer/json.rb +0 -67
  61. data/lib/roar/representer/transport/faraday.rb +0 -50
  62. data/lib/roar/representer/transport/net_http.rb +0 -59
  63. data/lib/roar/representer/transport/net_http/request.rb +0 -75
  64. data/lib/roar/representer/xml.rb +0 -61
@@ -1,6 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec path: '../'
4
-
5
- gem 'representable', '~> 1.7.0'
6
- gem "sinatra-contrib", :git => "git@github.com:apotonick/sinatra-contrib.git", :branch => "runner"
@@ -1,6 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec path: '../'
4
-
5
- gem 'representable', '~> 1.8.0'
6
- gem "sinatra-contrib", :git => "git@github.com:apotonick/sinatra-contrib.git", :branch => "runner"
@@ -1,39 +0,0 @@
1
- require "roar/representer/feature/http_verbs"
2
-
3
- module Roar
4
- # Automatically add accessors for properties and collections. Also mixes in HttpVerbs.
5
- module Representer
6
- module Feature
7
- module Client
8
- include HttpVerbs
9
-
10
- def self.extended(base)
11
- base.instance_eval do
12
- representable_attrs.each do |attr|
13
- next unless attr.instance_of? Representable::Definition # ignore hyperlinks etc for now.
14
- name = attr.name
15
-
16
- # TODO: could anyone please make this better?
17
- instance_eval %Q{
18
- def #{name}=(v)
19
- @#{name} = v
20
- end
21
-
22
- def #{name}
23
- @#{name}
24
- end
25
- }
26
- end
27
- end
28
- end
29
-
30
- # DISCUSS: should we just override #serialize here? otherwise if you later include Hypermedia, it'll run before that method.
31
- def before_serialize(options={})
32
- options[:links] ||= false
33
-
34
- super(options)
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,95 +0,0 @@
1
- require 'roar/representer/transport/net_http'
2
-
3
- module Roar
4
- # Gives HTTP-power to representers. They can serialize, send, process and deserialize HTTP-requests.
5
- module Representer
6
- module Feature
7
- module HttpVerbs
8
-
9
- class << self
10
- attr_accessor :transport_engine
11
-
12
- def included(base)
13
- base.extend ClassMethods
14
- end
15
- end
16
- self.transport_engine = ::Roar::Representer::Transport::NetHTTP
17
-
18
-
19
- module ClassMethods
20
- # GETs +url+ with +format+ and returns deserialized represented object.
21
- def get(*args)
22
- new.get(*args)
23
- end
24
- end
25
-
26
-
27
- attr_writer :transport_engine
28
- def transport_engine
29
- @transport_engine || HttpVerbs.transport_engine
30
- end
31
-
32
- # Serializes the object, POSTs it to +url+ with +format+, deserializes the returned document
33
- # and updates properties accordingly.
34
- def post(*args, &block)
35
- options = handle_deprecated_args(serialize, *args)
36
- response = http.post_uri(options, &block)
37
- handle_response(response)
38
- end
39
-
40
- # GETs +url+ with +format+, deserializes the returned document and updates properties accordingly.
41
- def get(*args, &block)
42
- response = http.get_uri(*args, &block)
43
- handle_response(response)
44
- end
45
-
46
- # Serializes the object, PUTs it to +url+ with +format+, deserializes the returned document
47
- # and updates properties accordingly.
48
- def put(*args, &block)
49
- options = handle_deprecated_args(serialize, *args)
50
- response = http.put_uri(options, &block)
51
- handle_response(response)
52
- self
53
- end
54
-
55
- def patch(*args, &block)
56
- options = handle_deprecated_args(serialize, *args)
57
- response = http.patch_uri(options, &block)
58
- handle_response(response)
59
- self
60
- end
61
-
62
- def delete(*args, &block)
63
- http.delete_uri(*args, &block)
64
- self
65
- end
66
-
67
- private
68
- def handle_response(response)
69
- document = response.body
70
- deserialize(document)
71
- end
72
-
73
- def http
74
- transport_engine.new
75
- end
76
-
77
- def handle_deprecated_args(body, *args) # TODO: remove in 1.0.
78
- options = args.first
79
-
80
- if args.size > 1
81
- warn %{DEPRECATION WARNING: #get, #post, #put, #delete and #patch no longer accept positional arguments. Please call them as follows:
82
- get(uri: "http://localhost/songs", as: "application/json")
83
- post(uri: "http://localhost/songs", as: "application/json")
84
- Thank you and have a beautiful day.}
85
- options = {:uri => args[0], :as => args[1]} if args.size == 2
86
- options = {:uri => args[0], :as => args[2]}
87
- end
88
-
89
- options[:body] = body
90
- options
91
- end
92
- end
93
- end
94
- end
95
- end
@@ -1,175 +0,0 @@
1
- module Roar
2
- module Representer
3
- module Feature
4
- # Define hypermedia links in your representations.
5
- #
6
- # Example:
7
- #
8
- # class Order
9
- # include Roar::Representer::JSON
10
- #
11
- # property :id
12
- #
13
- # link :self do
14
- # "http://orders/#{id}"
15
- # end
16
- #
17
- # If you want more attributes, just pass a hash to #link.
18
- #
19
- # link :rel => :next, :title => "Next, please!" do
20
- # "http://orders/#{id}"
21
- # end
22
- #
23
- # If you need dynamic attributes, the block can return a hash.
24
- #
25
- # link :preview do
26
- # {:href => image.url, :title => image.name}
27
- # end
28
- #
29
- # Sometimes you need values from outside when the representation links are rendered. Just pass them
30
- # to the render method, they will be available as block parameters.
31
- #
32
- # link :self do |opts|
33
- # "http://orders/#{opts[:id]}"
34
- # end
35
- #
36
- # model.to_json(:id => 1)
37
- module Hypermedia
38
- def self.included(base)
39
- base.extend ClassMethods
40
- base.extend InheritableArray
41
- end
42
-
43
- def before_serialize(options={})
44
- super(options) # Representer::Base
45
- prepare_links!(options) unless options[:links] == false # DISCUSS: doesn't work when links are already setup (e.g. from #deserialize).
46
- end
47
-
48
- attr_writer :links
49
-
50
- def links
51
- @links ||= LinkCollection.new
52
- end
53
-
54
- def links_array
55
- links.values # FIXME: move to LinkCollection#to_a.
56
- end
57
-
58
- def links_array=(ary)
59
- # FIXME: move to LinkCollection
60
- self.links= LinkCollection.new
61
- ary.each { |lnk| links.add(lnk) }
62
- end
63
-
64
- module LinkConfigsMethod
65
- def link_configs
66
- representable_attrs.inheritable_array(:links)
67
- end
68
- end
69
-
70
- include LinkConfigsMethod
71
-
72
- private
73
- def links_definition_options
74
- # TODO: this method is never called.
75
- [:links_array, {:as => :link, :class => Feature::Hypermedia::Hyperlink, :collection => true,
76
- :decorator_scope => true}] # TODO: merge with JSON.
77
- end
78
-
79
- # Setup hypermedia links by invoking their blocks. Usually called by #serialize.
80
- def prepare_links!(*args)
81
- # TODO: move this method to _links or something so it doesn't need to be called in #serialize.
82
- compile_links_for(link_configs, *args).each do |lnk|
83
- links.add(lnk) # TODO: move to LinkCollection.new.
84
- end
85
- end
86
-
87
- def compile_links_for(configs, *args)
88
- configs.collect do |config|
89
- options, block = config.first, config.last
90
- href = run_link_block(block, *args) or next
91
-
92
- prepare_link_for(href, options)
93
- end.compact # FIXME: make this less ugly.
94
- end
95
-
96
- def prepare_link_for(href, options)
97
- options = options.merge(href.is_a?(Hash) ? href : {:href => href})
98
- Hyperlink.new(options)
99
- end
100
-
101
- def run_link_block(block, *args)
102
- instance_exec(*args, &block)
103
- end
104
-
105
-
106
- class LinkCollection < Hash
107
- # DISCUSS: make Link#rel return string always.
108
- def [](rel)
109
- self.fetch(rel.to_s, nil)
110
- end
111
-
112
- def add(link)
113
- self[link.rel.to_s] = link
114
- end
115
- end
116
-
117
-
118
- module ClassMethods
119
- # Declares a hypermedia link in the document.
120
- #
121
- # Example:
122
- #
123
- # link :self do
124
- # "http://orders/#{id}"
125
- # end
126
- #
127
- # The block is executed in instance context, so you may call properties or other accessors.
128
- # Note that you're free to put decider logic into #link blocks, too.
129
- def link(options, &block)
130
- options = {:rel => options} unless options.is_a?(Hash)
131
- create_links_definition # this assures the links are rendered at the right position.
132
- link_configs << [options, block]
133
- end
134
-
135
- include LinkConfigsMethod
136
-
137
- private
138
- def create_links_definition
139
- return if representable_attrs.find { |d| d.is_a?(LinksDefinition) }
140
-
141
- options = links_definition_options # TODO: remove in 1.0.
142
- if Roar.representable_1_8?
143
- opt = options.last
144
- opt[:exec_context] = :decorator
145
- opt.delete(:decorator_scope)
146
- end
147
-
148
- representable_attrs << LinksDefinition.new(*options)
149
- end
150
- end
151
-
152
- class LinksDefinition < Representable::Definition
153
- end
154
-
155
-
156
- require "ostruct"
157
- # An abstract hypermedia link with arbitrary attributes.
158
- class Hyperlink < OpenStruct
159
- include Enumerable
160
-
161
- def each(*args, &block)
162
- marshal_dump.each(*args, &block)
163
- end
164
-
165
- # FIXME: do we need this method any longer?
166
- def replace(hash)
167
- # #marshal_load requires symbol keys: http://apidock.com/ruby/v1_9_3_125/OpenStruct/marshal_load
168
- marshal_load(hash.inject({}) { |h, (k,v)| h[k.to_sym] = v; h })
169
- self
170
- end
171
- end
172
- end
173
- end
174
- end
175
- end
@@ -1,67 +0,0 @@
1
- require 'roar/representer'
2
- require 'roar/representer/feature/hypermedia'
3
- require 'representable/json'
4
-
5
- module Roar
6
- require 'representable/version'
7
- def self.representable_1_8? # TODO: remove me in 1.0.
8
- Representable::VERSION =~ /^1.8/
9
- end
10
-
11
- module Representer
12
- module JSON
13
- def self.included(base)
14
- base.class_eval do
15
- include Representer
16
- include Representable::JSON
17
-
18
- extend ClassMethods
19
- include InstanceMethods # otherwise Representable overrides our #to_json.
20
- end
21
- end
22
-
23
- module InstanceMethods
24
- def to_hash(*args)
25
- before_serialize(*args)
26
- super
27
- end
28
-
29
- def from_json(document, options={})
30
- document = '{}' if document.nil? or document.empty?
31
-
32
- super
33
- end
34
-
35
- # Generic entry-point for rendering.
36
- def serialize(*args)
37
- to_json(*args)
38
- end
39
-
40
- def deserialize(*args)
41
- from_json(*args)
42
- end
43
- end
44
-
45
-
46
- module ClassMethods
47
- def deserialize(*args)
48
- from_json(*args)
49
- end
50
-
51
- # TODO: move to instance method, or remove?
52
- def links_definition_options
53
- # FIXME: this doesn't belong into the generic JSON representer.
54
- [:links_array, {:as => :links, :class => Feature::Hypermedia::Hyperlink, :extend => HyperlinkRepresenter, :collection => true,
55
- :decorator_scope => true}]
56
- end
57
- end
58
-
59
-
60
- require "representable/json/hash"
61
- # Represents a hyperlink in standard roar+json hash representation.
62
- module HyperlinkRepresenter
63
- include Representable::JSON::Hash
64
- end
65
- end
66
- end
67
- end
@@ -1,50 +0,0 @@
1
- require 'faraday'
2
-
3
- module Roar
4
- module Representer
5
- module Transport
6
- # Advanced implementation of the HTTP verbs with the Faraday HTTP library
7
- # (which can, in turn, use adapters based on Net::HTTP or libcurl)
8
- #
9
- # Depending on how the Faraday middleware stack is configured, this
10
- # Transport can support features such as HTTP error code handling,
11
- # redirects, etc.
12
- #
13
- # @see http://rubydoc.info/gems/faraday/file/README.md Faraday README
14
- class Faraday
15
-
16
- def get_uri(uri, as, *args)
17
- build_connection(uri, as).get
18
- end
19
-
20
- def post_uri(uri, body, as, *args)
21
- build_connection(uri, as).post(nil, body)
22
- end
23
-
24
- def put_uri(uri, body, as, *args)
25
- build_connection(uri, as).put(nil, body)
26
- end
27
-
28
- def patch_uri(uri, body, as, *args)
29
- build_connection(uri, as).patch(nil, body)
30
- end
31
-
32
- def delete_uri(uri, as, *args)
33
- build_connection(uri, as).delete
34
- end
35
-
36
- private
37
-
38
- def build_connection(uri, as)
39
- ::Faraday::Connection.new(
40
- :url => uri,
41
- :headers => { :accept => as, :content_type => as }
42
- ) do |builder|
43
- builder.use ::Faraday::Response::RaiseError
44
- builder.adapter ::Faraday.default_adapter
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end