restfulie 0.6.0 → 0.7.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 (74) hide show
  1. data/README.textile +83 -7
  2. data/Rakefile +98 -13
  3. data/lib/restfulie/client/base.rb +48 -53
  4. data/lib/restfulie/client/configuration.rb +69 -0
  5. data/lib/restfulie/client/http/adapter.rb +487 -0
  6. data/lib/restfulie/client/http/atom_ext.rb +87 -0
  7. data/lib/restfulie/client/http/cache.rb +28 -0
  8. data/lib/restfulie/client/http/error.rb +80 -0
  9. data/lib/restfulie/client/http/marshal.rb +147 -0
  10. data/lib/restfulie/client/http.rb +13 -0
  11. data/lib/restfulie/client.rb +8 -56
  12. data/lib/restfulie/common/builder/builder_base.rb +58 -0
  13. data/lib/restfulie/common/builder/helpers.rb +22 -0
  14. data/lib/restfulie/common/builder/marshalling/atom.rb +197 -0
  15. data/lib/restfulie/common/builder/marshalling/base.rb +12 -0
  16. data/lib/restfulie/common/builder/marshalling/json.rb +2 -0
  17. data/lib/restfulie/common/builder/marshalling.rb +16 -0
  18. data/lib/restfulie/common/builder/rules/collection_rule.rb +10 -0
  19. data/lib/restfulie/common/builder/rules/link.rb +20 -0
  20. data/lib/restfulie/common/builder/rules/links.rb +9 -0
  21. data/lib/restfulie/common/builder/rules/member_rule.rb +8 -0
  22. data/lib/restfulie/common/builder/rules/namespace.rb +25 -0
  23. data/lib/restfulie/common/builder/rules/rules_base.rb +76 -0
  24. data/lib/restfulie/common/builder.rb +16 -0
  25. data/lib/restfulie/common/errors.rb +9 -0
  26. data/lib/restfulie/{logger.rb → common/logger.rb} +3 -5
  27. data/lib/restfulie/common/representation/atom.rb +48 -0
  28. data/lib/restfulie/common/representation/generic.rb +33 -0
  29. data/lib/restfulie/common/representation/xml.rb +24 -0
  30. data/lib/restfulie/common/representation.rb +10 -0
  31. data/lib/restfulie/common.rb +23 -0
  32. data/lib/restfulie/server/action_controller/base.rb +31 -0
  33. data/lib/restfulie/server/action_controller/params_parser.rb +62 -0
  34. data/lib/restfulie/server/action_controller/restful_responder.rb +39 -0
  35. data/lib/restfulie/server/action_controller/routing/restful_route.rb +14 -0
  36. data/lib/restfulie/server/action_controller/routing.rb +12 -0
  37. data/lib/restfulie/server/action_controller.rb +15 -0
  38. data/lib/restfulie/server/action_view/helpers.rb +45 -0
  39. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +15 -0
  40. data/lib/restfulie/server/action_view/template_handlers.rb +13 -0
  41. data/lib/restfulie/server/action_view.rb +8 -0
  42. data/lib/restfulie/server/configuration.rb +21 -0
  43. data/lib/restfulie/server/core_ext/array.rb +45 -0
  44. data/lib/restfulie/server/core_ext.rb +1 -0
  45. data/lib/restfulie/server/restfulie_controller.rb +1 -17
  46. data/lib/restfulie/server.rb +15 -0
  47. data/lib/restfulie.rb +4 -72
  48. data/lib/vendor/atom/configuration.rb +24 -0
  49. data/lib/vendor/atom/pub.rb +250 -0
  50. data/lib/vendor/atom/xml/parser.rb +373 -0
  51. data/lib/vendor/atom.rb +771 -0
  52. metadata +94 -33
  53. data/lib/restfulie/client/atom_media_type.rb +0 -75
  54. data/lib/restfulie/client/cache.rb +0 -103
  55. data/lib/restfulie/client/entry_point.rb +0 -94
  56. data/lib/restfulie/client/extensions/http.rb +0 -116
  57. data/lib/restfulie/client/helper.rb +0 -28
  58. data/lib/restfulie/client/instance.rb +0 -158
  59. data/lib/restfulie/client/request_execution.rb +0 -321
  60. data/lib/restfulie/client/state.rb +0 -36
  61. data/lib/restfulie/media_type.rb +0 -143
  62. data/lib/restfulie/media_type_control.rb +0 -115
  63. data/lib/restfulie/media_type_defaults.rb +0 -51
  64. data/lib/restfulie/server/atom_media_type.rb +0 -115
  65. data/lib/restfulie/server/base.rb +0 -91
  66. data/lib/restfulie/server/controller.rb +0 -122
  67. data/lib/restfulie/server/instance.rb +0 -102
  68. data/lib/restfulie/server/marshalling.rb +0 -47
  69. data/lib/restfulie/server/opensearch/description.rb +0 -54
  70. data/lib/restfulie/server/opensearch.rb +0 -18
  71. data/lib/restfulie/server/transition.rb +0 -93
  72. data/lib/restfulie/unmarshalling.rb +0 -131
  73. data/lib/vendor/jeokkarak/hashi.rb +0 -65
  74. data/lib/vendor/jeokkarak/jeokkarak.rb +0 -81
@@ -0,0 +1,147 @@
1
+ #Request builder for marshalled data that unmarshalls content after receiving it.
2
+ module Restfulie::Client::HTTP
3
+
4
+ module ResponseHolder
5
+ attr_accessor :response
6
+
7
+ def respond_to?(symbol)
8
+ respond_to_rel?(symbol.to_s) || super(symbol)
9
+ end
10
+
11
+ private
12
+ # whether this response contains specific relations
13
+ def respond_to_rel?(rel)
14
+ links.any? { |link| link.rel==rel }
15
+ end
16
+
17
+ end
18
+
19
+ module RequestMarshaller
20
+ include ::Restfulie::Client::HTTP::RequestBuilder
21
+
22
+ # accepts a series of media types by default
23
+ def initialize
24
+ @acceptable_mediatypes = "application/atom+xml"
25
+ end
26
+
27
+ @@representations = {
28
+ 'application/atom+xml' => ::Restfulie::Common::Representation::Atom,
29
+ 'application/xml' => ::Restfulie::Common::Representation::XmlD
30
+ }
31
+ def self.register_representation(media_type,representation)
32
+ @@representations[media_type] = representation
33
+ end
34
+
35
+ def self.content_type_for(media_type)
36
+ content_type = media_type.split(';')[0] # [/(.*?);/, 1]
37
+ type = @@representations[content_type]
38
+ type ? type.new : nil
39
+ end
40
+
41
+ def accepts(media_types)
42
+ @acceptable_mediatypes = media_types
43
+ @default_representation = @@representations[media_types]
44
+ raise "Undefined representation for #{media_types}" unless @default_representation
45
+ super
46
+ end
47
+
48
+ def raw
49
+ @raw = true
50
+ self
51
+ end
52
+
53
+ #Executes super and unmarshalls it
54
+ def request!(method, path, *args)
55
+ representation = do_conneg_and_choose_representation(method, path, *args)
56
+ if representation
57
+ if has_payload?(method, path, *args)
58
+ payload = get_payload(method, path, *args)
59
+ rel = self.respond_to?(:rel) ? self.rel : ""
60
+ payload = representation.marshal(payload, rel)
61
+ args = set_marshalled_payload(method, path, payload, *args)
62
+ end
63
+ args = add_representation_headers(method, path, representation, *args)
64
+ end
65
+ response = super(method, path, *args)
66
+ parse_response(response, representation)
67
+ end
68
+
69
+ private
70
+
71
+ # parses the http response.
72
+ # first checks if its a 201, redirecting to the resource location.
73
+ # otherwise check if its a raw request, returning the content itself.
74
+ # finally, tries to parse the content with a mediatype handler or returns the response itself.
75
+ def parse_response(response, representation)
76
+ if response.code == 201
77
+ location = response.headers['location']
78
+ Restfulie.at(location).accepts(@acceptable_mediatypes).get!
79
+ elsif @raw
80
+ response
81
+ elsif !response.body.empty?
82
+ representation = RequestMarshaller.content_type_for(response.headers['content-type']) || Restfulie::Common::Representation::Generic.new
83
+ unmarshalled = representation.unmarshal(response.body)
84
+ unmarshalled.extend(ResponseHolder)
85
+ unmarshalled.response = response
86
+ unmarshalled
87
+ else
88
+ response
89
+ end
90
+ end
91
+
92
+ def content_type_for(media_type)
93
+ @@representations[media_type.split(';')[0]].new # [/(.*?);/, 1]
94
+ end
95
+
96
+ def do_conneg_and_choose_representation(method, path, *args)
97
+ #TODO make a request to server (conneg)
98
+ representation = @default_representation || @default_representation = @@representations['application/atom+xml']
99
+ representation.new
100
+ end
101
+
102
+ def has_payload?(method, path, *args)
103
+ [:put,:post].include?(method)
104
+ end
105
+
106
+ def get_payload(method, path, *args)
107
+ args.extract_options! #remove header
108
+ args.shift #payload
109
+ end
110
+
111
+ def set_marshalled_payload(method, path, payload, *args)
112
+ headers = args.extract_options!
113
+ args.shift #old payload
114
+ args << payload << headers
115
+ args
116
+ end
117
+
118
+ def add_representation_headers(method, path, representation, *args)
119
+ headers = args.extract_options!
120
+ args << representation.headers[method]
121
+ args
122
+ end
123
+
124
+ end
125
+
126
+ #=This class includes RequestBuilder module.
127
+ class RequestMarshallerExecutor
128
+ include RequestMarshaller
129
+
130
+ # * <tt> host (e.g. 'http://restfulie.com') </tt>
131
+ # * <tt> default_headers (e.g. {'Cache-control' => 'no-cache'} ) </tt>
132
+ def initialize(host, default_headers = {})
133
+ self.host=host
134
+ self.default_headers=default_headers
135
+ end
136
+
137
+ def at(path)
138
+ @path = path
139
+ self
140
+ end
141
+ def path
142
+ @path
143
+ end
144
+ end
145
+
146
+ end
147
+
@@ -0,0 +1,13 @@
1
+ module Restfulie::Client::HTTP#:nodoc:
2
+ end
3
+
4
+ %w(
5
+ error
6
+ adapter
7
+ cache
8
+ marshal
9
+ atom_ext
10
+ ).each do |file|
11
+ require "restfulie/client/http/#{file}"
12
+ end
13
+
@@ -1,60 +1,12 @@
1
- #
2
- # Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
3
- # All rights reserved.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
1
+ require 'restfulie/common'
17
2
 
18
- require 'restfulie/logger'
3
+ module Restfulie::Client; end
19
4
 
20
- require 'net/http'
21
- require 'uri'
22
- require 'vendor/jeokkarak/jeokkarak'
23
-
24
- require 'restfulie/media_type'
25
- require 'restfulie/client/atom_media_type'
26
- require 'restfulie/client/base'
27
- require 'restfulie/client/entry_point'
28
- require 'restfulie/client/helper'
29
- require 'restfulie/client/instance'
30
- require 'restfulie/client/request_execution'
31
- require 'restfulie/client/state'
32
- require 'restfulie/client/cache'
33
- require 'restfulie/unmarshalling'
34
-
35
- module Restfulie
36
-
37
- class << self
38
- attr_accessor :cache_provider
39
- end
40
-
41
- # Extends your class to support restfulie-client side's code.
42
- # This will extends Restfulie::Client::Base methods as class methods,
43
- # Restfulie::Client::Instance as instance methods and Restfulie::Unmarshalling as class methods.
44
- def uses_restfulie
45
- extend Restfulie::Client::Base
46
- include Restfulie::Client::Instance
47
- extend Restfulie::Unmarshalling
48
- end
49
-
50
- end
51
-
52
- Object.extend Restfulie
53
-
54
- include ActiveSupport::CoreExtensions::Hash
55
-
56
- class Hashi::CustomHash
57
- uses_restfulie
5
+ %w(
6
+ http
7
+ configuration
8
+ base
9
+ ).each do |file|
10
+ require "restfulie/client/#{file}"
58
11
  end
59
12
 
60
- Restfulie.cache_provider = Restfulie::BasicCache.new
@@ -0,0 +1,58 @@
1
+ class Restfulie::Common::Builder::Base
2
+ attr_accessor :rules_blocks
3
+ attr_accessor :object
4
+
5
+ # TODO: Configurable
6
+ OPTIONS_DEFAULT = {
7
+ :eagerload => true,
8
+ :default_rule => true
9
+ }
10
+
11
+ def initialize(object, rules_blocks = [], options = {})
12
+ @options = OPTIONS_DEFAULT.merge(options)
13
+ @object = object
14
+ @rules_blocks = rules_blocks
15
+ end
16
+
17
+ # Remove to_json from ActiveSupport in the class
18
+ # I want my own to_json
19
+ undef_method :to_json if respond_to?(:to_json)
20
+
21
+ def respond_to?(symbol, include_private = false)
22
+ !marshalling_class(symbol).nil? || super
23
+ end
24
+
25
+ def method_missing(symbol, *args)
26
+ unless (marshalling = marshalling_class(symbol)).nil?
27
+ return builder(marshalling, *args)
28
+ end
29
+ super
30
+ end
31
+
32
+ private
33
+
34
+ def builder(marshalling, options = {})
35
+ @object.class.ancestors.include?(Enumerable) ? builder_collection(marshalling, options) : builder_member(marshalling, options)
36
+ end
37
+
38
+ def builder_member(marshalling, options = {})
39
+ marshalling.new(@object, rules_blocks).builder_member(@options.merge(options))
40
+ end
41
+
42
+ def builder_collection(marshalling, options = {})
43
+ marshalling.new(@object, rules_blocks).builder_collection(@options.merge(options))
44
+ end
45
+
46
+ def marshalling_class(method)
47
+ if marshalling_name = method.to_s.match(/to_(.*)/)
48
+ marshalling = marshalling_name[1].downcase.capitalize.to_sym
49
+ if Restfulie::Common::Builder::Marshalling.const_defined?(marshalling)
50
+ begin
51
+ Restfulie::Common::Builder::Marshalling.const_get(marshalling)
52
+ rescue NameError
53
+ raise Restfulie::Common::Error::UndefinedMarshallingError.new("Marshalling #{marshalling} not found.")
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ module Restfulie::Common::Builder::Helpers
2
+
3
+ def describe_member(member, options = {}, &block)
4
+ create_builder(member, options, &block)
5
+ end
6
+
7
+ def describe_collection(collection, options = {}, &block)
8
+ create_builder(collection, options, &block)
9
+ end
10
+
11
+ # Helper to create objects link
12
+ def link(*args)
13
+ Restfulie::Common::Builder::Rules::Link.new(*args)
14
+ end
15
+
16
+ private
17
+
18
+ def create_builder(object, options, &block)
19
+ Restfulie::Common::Builder::Base.new(object, block_given? ? [block] : [], options)
20
+ end
21
+
22
+ end
@@ -0,0 +1,197 @@
1
+ class Restfulie::Common::Builder::Marshalling::Atom < Restfulie::Common::Builder::Marshalling::Base
2
+ include ActionController::UrlWriter
3
+ include Restfulie::Common::Builder::Helpers
4
+ include Restfulie::Common::Error
5
+
6
+ ATOM_ATTRIBUTES = [
7
+ :title, :id, :updated, # Required
8
+ :author, :links, # Recommended
9
+ :category, :contributor, :rights # Optional
10
+ ]
11
+
12
+ ATOM_ATTRIBUTES_ENTRY = ATOM_ATTRIBUTES + [
13
+ :content, :summary, # Required
14
+ :published, :source # Optional
15
+ ]
16
+
17
+ ATOM_ATTRIBUTES_FEED = ATOM_ATTRIBUTES + [
18
+ :generator, :icon, :logo, :subtitle # Optional
19
+ ]
20
+
21
+ ATTRIBUTES_ALREADY_IN_ATOM_SPEC = [
22
+ "id", "created_at", "updated_at", "title"
23
+ ]
24
+
25
+ def initialize(object, rules)
26
+ @object = object
27
+ @rules = rules
28
+ end
29
+
30
+ def builder_collection(options = {})
31
+ builder_feed(@object, @rules, options).to_xml
32
+ end
33
+
34
+ def builder_member(options = {})
35
+ builder_entry(@object, @rules, options).to_xml
36
+ end
37
+
38
+ private
39
+
40
+ def builder_feed(objects, rules_blocks, options = {})
41
+ rule = Restfulie::Common::Builder::CollectionRule.new(rules_blocks)
42
+
43
+ rule.blocks.unshift(default_collection_rule) if options[:default_rule]
44
+ rule.metaclass.send(:attr_accessor, *ATOM_ATTRIBUTES_FEED)
45
+ rule.apply(objects, options)
46
+
47
+ atom = ::Atom::Feed.new do |feed|
48
+ # Set values
49
+ (ATOM_ATTRIBUTES_FEED - [:links]).each do |field|
50
+ feed.send("#{field}=".to_sym, rule.send(field)) unless rule.send(field).nil?
51
+ end
52
+
53
+ # Namespaces
54
+ builder_namespaces(rule.namespaces, feed)
55
+
56
+ # Transitions
57
+ rule.links.each do |link|
58
+ atom_link = {:rel => link.rel, :href => link.href, :type => (link.type || 'application/atom+xml')}
59
+ feed.links << ::Atom::Link.new(atom_link) unless atom_link[:href].nil?
60
+ end
61
+
62
+ # Entries
63
+ options.delete(:values)
64
+ member_options = options.merge(rule.members_options || {})
65
+ objects.each do |member|
66
+ feed.entries << builder_entry(member, rule.members_blocks || [], member_options)
67
+ end
68
+ end
69
+ end
70
+
71
+ # TODO: Validate of the required fields
72
+ def default_collection_rule
73
+ Proc.new do |collection_rule, objects, options|
74
+ # Passed values
75
+ (options[:values] || {}).each { |key, value| collection_rule.send("#{key}=".to_sym, value)}
76
+
77
+ # Default values
78
+ collection_rule.id ||= options[:self]
79
+ collection_rule.title ||= "#{objects.first.class.to_s.pluralize.demodulize} feed"
80
+ collection_rule.updated ||= updated_collection(objects)
81
+
82
+ # Transitions
83
+ collection_rule.links << link(:rel => :self, :href => options[:self]) unless options[:self].nil?
84
+ end
85
+ end
86
+
87
+ def builder_entry(object, rules_blocks, options = {})
88
+ rule = Restfulie::Common::Builder::MemberRule.new(rules_blocks)
89
+ options = namespace_enhance(options)
90
+
91
+ rule.blocks.unshift(default_member_rule) if options[:default_rule]
92
+ rule.metaclass.send(:attr_accessor, *ATOM_ATTRIBUTES_ENTRY)
93
+ rule.apply(object, options)
94
+
95
+ atom = ::Atom::Entry.new do |entry|
96
+ # Set values
97
+ (ATOM_ATTRIBUTES_ENTRY - [:links]).each do |field|
98
+ entry.send("#{field}=".to_sym, rule.send(field)) unless rule.send(field).nil?
99
+ end
100
+
101
+ # Namespaces
102
+ builder_namespaces(rule.namespaces, entry)
103
+
104
+ # Transitions
105
+ rule.links.each do |link|
106
+ atom_link = {:rel => link.rel, :href => link.href, :type => link.type}
107
+
108
+ # Self
109
+ if link.href.nil?
110
+ if link.rel == "self"
111
+ path = object
112
+ else
113
+ association = object.class.reflect_on_all_associations.find { |a| a.name.to_s == link.rel }
114
+ path = (association.macro == :has_many) ? [object, association.name] : object.send(association.name) unless association.nil?
115
+ end
116
+ atom_link[:href] = polymorphic_url(path, :host => host) rescue nil
117
+ atom_link[:type] = link.type || 'application/atom+xml'
118
+ end
119
+
120
+ entry.links << ::Atom::Link.new(atom_link) unless atom_link[:href].nil?
121
+ end
122
+ end
123
+ end
124
+
125
+ def default_member_rule
126
+ Proc.new do |member_rule, object, options|
127
+ # Passed values
128
+ (options[:values] || {}).each { |key, value| set_attribute(member_rule, key, value) }
129
+
130
+ # Default values
131
+ member_rule.id ||= polymorphic_url(object, :host => host) rescue nil
132
+ member_rule.title ||= object.respond_to?(:title) && !object.title.nil? ? object.title : "Entry about #{object.class.to_s.demodulize}"
133
+ member_rule.updated ||= object.updated_at if object.respond_to?(:updated_at)
134
+
135
+ # Namespace
136
+ unless options[:namespace].nil?
137
+ member_rule.namespace(object, options[:namespace][:uri], options[:namespace])
138
+ end
139
+ end
140
+ end
141
+
142
+ def updated_collection(objects)
143
+ objects.map { |item| item.updated_at if item.respond_to?(:updated_at) }.compact.max || Time.now
144
+ end
145
+
146
+ def builder_namespaces(namespaces, atom)
147
+ kclass = atom.class
148
+ namespaces.each do |ns|
149
+ register_namespace(ns.namespace, ns.uri, kclass)
150
+ ns.each do |key, value|
151
+ unless ATTRIBUTES_ALREADY_IN_ATOM_SPEC.include?(key.to_s)
152
+ register_element(ns.namespace, key, kclass)
153
+ atom.send("#{ns.namespace}_#{key}=".to_sym, value)
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ def host
160
+ # TODO: If we split restfulie into 2 separate gems, we may need not to use Restfulie::Server
161
+ # inside Restfulie::Common
162
+ Restfulie::Server::Configuration.host
163
+ end
164
+
165
+ def register_namespace(namespace, uri, klass)
166
+ klass.add_extension_namespace(namespace, uri) unless klass.known_namespaces.include? uri
167
+ end
168
+
169
+ def register_element(namespace, attribute, klass)
170
+ attribute = "#{namespace}:#{attribute}"
171
+ klass.element(attribute) if element_unregistered?(attribute, klass)
172
+ end
173
+
174
+ def element_unregistered?(element, klass)
175
+ klass.element_specs.select { |k,v| v.name == element }.empty?
176
+ end
177
+
178
+ # TODO : Move error handling to class rule, maybe?
179
+ def set_attribute(rule, attribute, value)
180
+ begin
181
+ rule.send("#{attribute}=".to_sym, value)
182
+ rescue NoMethodError
183
+ raise AtomMarshallingError.new("Attribute #{attribute} unsupported in Atom #{rule_type_name(rule)}.")
184
+ end
185
+ end
186
+
187
+ def rule_type_name(rule)
188
+ rule.kind_of?(Restfulie::Common::Builder::MemberRule) ? 'Entry' : 'Feed'
189
+ end
190
+
191
+ def namespace_enhance(options)
192
+ if !options[:namespace].nil? && options[:namespace].kind_of?(String)
193
+ options[:namespace] = { :uri => options[:namespace], :eager_load => true }
194
+ end
195
+ options
196
+ end
197
+ end
@@ -0,0 +1,12 @@
1
+ class Restfulie::Common::Builder::Marshalling::Base
2
+ def initialize(*args)
3
+ end
4
+
5
+ def builder_member(options = {})
6
+ "#{self.class.to_s.demodulize} Marshalling not implemented"
7
+ end
8
+
9
+ def builder_collection(options = {})
10
+ "#{self.class.to_s.demodulize} Marshalling not implemented"
11
+ end
12
+ end
@@ -0,0 +1,2 @@
1
+ class Restfulie::Common::Builder::Marshalling::Json < Restfulie::Common::Builder::Marshalling::Base
2
+ end
@@ -0,0 +1,16 @@
1
+ module Restfulie::Common::Builder::Marshalling
2
+ class << self
3
+ def add_autoload_path(path)
4
+ if File.directory?(path)
5
+ Dir["#{path}/*.rb"].each do |file|
6
+ marshalling_class = File.basename(file, ".rb").downcase.classify.to_sym
7
+ self.autoload(marshalling_class, file) if !self.const_defined?(marshalling_class) && self.autoload?(marshalling_class).nil?
8
+ end
9
+ else
10
+ raise Restfulie::Common::Error::MarshallingError.new("#{path} is not a path.")
11
+ end
12
+ end
13
+ end
14
+
15
+ self.add_autoload_path(File.join(File.dirname(__FILE__), 'marshalling'))
16
+ end
@@ -0,0 +1,10 @@
1
+ class Restfulie::Common::Builder::CollectionRule < Restfulie::Common::Builder::Rules::Base
2
+ attr_reader :members_blocks
3
+ attr_reader :members_options
4
+
5
+ def describe_members(options = {}, &block)
6
+ @members_blocks = block_given? ? [block] : []
7
+ @members_options = options
8
+ end
9
+
10
+ end
@@ -0,0 +1,20 @@
1
+ class Restfulie::Common::Builder::Rules::Link
2
+ # Required
3
+ attr_accessor :href
4
+
5
+ # Optional
6
+ attr_accessor :rel, :type
7
+ attr_accessor :hreflang, :title, :length
8
+
9
+ # TODO: Inline resource and collection support
10
+ def initialize(options = {})
11
+ options = { :rel => options } unless options.kind_of?(Hash)
12
+ options.each do |k, i|
13
+ self.send("#{k}=".to_sym, i)
14
+ end
15
+ end
16
+
17
+ def rel=(value)
18
+ @rel = value.kind_of?(String) ? value : value.to_s
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ class Restfulie::Common::Builder::Rules::Links < Array
2
+ alias_method :old_delete, :delete
3
+
4
+ def delete(item)
5
+ item = item.to_s if item.kind_of?(Symbol)
6
+ deleted = old_delete(item)
7
+ deleted.nil? ? old_delete(find { |i| i.rel == item }) : deleted
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ class Restfulie::Common::Builder::MemberRule < Restfulie::Common::Builder::Rules::Base
2
+
3
+ # Recommended
4
+ # attr_accessor :content, :summary # Not implemented
5
+
6
+ # Optional
7
+ # attr_accessor :source # Not implemented
8
+ end
@@ -0,0 +1,25 @@
1
+ class Restfulie::Common::Builder::Rules::Namespace < Hash
2
+ attr_reader :namespace
3
+ attr_reader :uri
4
+
5
+ def initialize(ns, uri, *args)
6
+ @namespace = ns.to_sym
7
+ self.uri = uri
8
+ super(*args)
9
+ end
10
+
11
+ def uri=(value)
12
+ raise Restfulie::Common::Error::NameSpaceError.new('Namespace can not be blank uri.') if value.blank?
13
+ @uri = value
14
+ end
15
+
16
+ def method_missing(symbol, *args)
17
+ if ((key = symbol.to_s.match(/(.*)=/)) && args.size >= 1)
18
+ self[key[1].to_sym] = args.first
19
+ elsif(keys.include?(symbol))
20
+ self[symbol]
21
+ else
22
+ super
23
+ end
24
+ end
25
+ end