restfulie 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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