rpc-mapper 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -30,10 +30,19 @@ Rake::GemPackageTask.new(spec) do |pkg|
30
30
  pkg.gem_spec = spec
31
31
  end
32
32
 
33
- Rake::TestTask.new do |t|
34
- t.libs << 'test'
35
- t.test_files = FileList["test/**/*_test.rb"]
36
- t.verbose = true
33
+ [:rails2, :rails3].each do |name|
34
+
35
+ Rake::TestTask.new("test_#{name}") do |t|
36
+ t.libs << 'test'
37
+ t.ruby_opts << "-r load_#{name}"
38
+ t.test_files = FileList["test/**/*_test.rb"]
39
+ t.verbose = true
40
+ end
41
+
42
+ end
43
+
44
+ desc "Test all gem versions"
45
+ task :test => [:test_rails2, :test_rails3] do
37
46
  end
38
47
 
39
48
  begin
@@ -4,33 +4,52 @@ module RPCMapper::Adapters
4
4
  class AbstractAdapter
5
5
  include RPCMapper::Logger
6
6
 
7
- attr_accessor :options
7
+ attr_accessor :config
8
+ attr_reader :type
8
9
  @@registered_adapters ||= {}
9
10
 
10
- def initialize(options={})
11
- @options = options.dup
11
+ def initialize(type, config)
12
+ @type = type.to_sym
13
+ @configuration_contexts = config.is_a?(Array) ? config : [config]
12
14
  end
13
15
 
14
- def self.create(type, options={})
15
- type = type ? @@registered_adapters[type.to_sym] : self
16
- type.new(options)
16
+ def self.create(type, config)
17
+ klass = type ? @@registered_adapters[type.to_sym] : self
18
+ klass.new(type, config)
17
19
  end
18
20
 
19
- def call(procedure, options={})
20
- log(options, "#{service_log_prefix} #{procedure}") { self.service.call.data_server.send(procedure, options) }
21
+ def extend_adapter(config)
22
+ self.class.create(self.type, @configuration_contexts + [*config])
21
23
  end
22
24
 
23
- def service
24
- raise NotImplementedError, "You must not use the AbstractAdapter. Implement an adapter that extends the AbstractAdapter class and overrides this method."
25
+ def config
26
+ @config ||= build_configuration
25
27
  end
26
28
 
27
- def service_log_prefix
28
- "RPC"
29
+ def read(options)
30
+ raise NotImplementedError, "You must not use the abstract adapter. Implement an adapter that extends the RPCMapper::Adapters::Abstract::Base class and overrides this method."
31
+ end
32
+
33
+ def write(object)
34
+ raise NotImplementedError, "You must not use the abstract adapter. Implement an adapter that extends the RPCMapper::Adapters::Abstract::Base class and overrides this method."
35
+ end
36
+
37
+ def delete(object)
38
+ raise NotImplementedError, "You must not use the abstract adapter. Implement an adapter that extends the RPCMapper::Adapters::Abstract::Base class and overrides this method."
29
39
  end
30
40
 
31
41
  def self.register_as(name)
32
42
  @@registered_adapters[name.to_sym] = self
33
43
  end
34
44
 
45
+ private
46
+
47
+ # TRP: Run each configure block in order of class hierarchy / definition and merge the results.
48
+ def build_configuration
49
+ @configuration_contexts.collect do |config_block|
50
+ config_block.is_a?(Hash) ? config_block : OpenStruct.new.tap { |os| config_block.call(os) }.marshal_dump
51
+ end.inject({}) { |sum, config| sum.merge(config) }
52
+ end
53
+
35
54
  end
36
55
  end
@@ -1,9 +1,27 @@
1
+ autoload :BERTRPC, 'bertrpc'
2
+
1
3
  module RPCMapper::Adapters
2
4
  class BERTRPCAdapter < RPCMapper::Adapters::AbstractAdapter
3
5
  register_as :bertrpc
4
6
 
7
+ @@service_pool ||= {}
8
+
5
9
  def service
6
- @service ||= BERTRPC::Service.new(self.options[:host], self.options[:port])
10
+ @@service_pool["#{config[:host]}:#{config[:port]}"] ||= BERTRPC::Service.new(self.config[:host], self.config[:port])
11
+ end
12
+
13
+ def read(options)
14
+ log(options, "RPC #{config[:service]}") { self.service.call.send(self.namespace).send(self.service_name, options.merge(config[:default_options] || {})) }
15
+ end
16
+
17
+ protected
18
+
19
+ def namespace
20
+ self.config[:namespace]
21
+ end
22
+
23
+ def service_name
24
+ self.config[:service]
7
25
  end
8
26
 
9
27
  end
@@ -0,0 +1,91 @@
1
+ autoload :Net, 'net/http'
2
+ autoload :URI, 'uri'
3
+
4
+ module RPCMapper::Adapters
5
+ class RestfulHTTPAdapter < RPCMapper::Adapters::AbstractAdapter
6
+ register_as :restful_http
7
+
8
+ def write(object)
9
+ params = build_params_from_attributes(object)
10
+ object.new_record? ? post_http(object, params) : put_http(object, params)
11
+ end
12
+
13
+ def delete(object)
14
+ delete_http(object)
15
+ end
16
+
17
+ protected
18
+
19
+ def post_http(object, params)
20
+ http_call(object, :post, params)
21
+ end
22
+
23
+ def put_http(object, params)
24
+ http_call(object, :put, params)
25
+ end
26
+
27
+ def delete_http(object)
28
+ http_call(object, :delete, self.config[:default_options])
29
+ end
30
+
31
+ def http_call(object, method, params={})
32
+ request_klass = case method
33
+ when :post then Net::HTTP::Post
34
+ when :put then Net::HTTP::Put
35
+ when :delete then Net::HTTP::Delete
36
+ end
37
+
38
+ req_uri = self.build_uri(object, method)
39
+
40
+ request = if method == :delete
41
+ request = request_klass.new([req_uri.path, req_uri.query].join('?'))
42
+ else
43
+ request = request_klass.new(req_uri.path)
44
+ request.set_form_data(params) unless method == :delete
45
+ request
46
+ end
47
+
48
+ self.log(params, "#{method.to_s.upcase} #{req_uri}") do
49
+ @last_response = Net::HTTP.new(req_uri.host, req_uri.port).start { |http| http.request(request) }
50
+ end
51
+ parse_response_code(@last_response)
52
+ end
53
+
54
+ def parse_response_code(response)
55
+ case response
56
+ when Net::HTTPSuccess, Net::HTTPRedirection
57
+ true
58
+ else
59
+ false
60
+ end
61
+ end
62
+
63
+ def build_params_from_attributes(object)
64
+ if self.config[:post_body_wrapper]
65
+ params = self.config[:default_options] || {}
66
+
67
+ object.attributes.each do |attribute, value|
68
+ params.merge!({"#{self.config[:post_body_wrapper]}[#{attribute}]" => value})
69
+ end
70
+
71
+ params
72
+ else
73
+ @attributes
74
+ end
75
+ end
76
+
77
+ def build_uri(object, method)
78
+ url = [self.config[:host].gsub(%r{/$}, ''), self.config[:service]]
79
+ url << object.id unless object.new_record?
80
+ uri = URI.parse "#{url.join('/')}#{self.config[:format]}"
81
+
82
+ # TRP: method DELETE has no POST body so we have to append any default options onto the query string
83
+ if method == :delete
84
+ uri.query = (self.config[:default_options] || {}).collect { |key, value| "#{key}=#{value}" }.join('&')
85
+ end
86
+
87
+ uri
88
+ end
89
+
90
+ end
91
+ end
@@ -2,3 +2,4 @@ module RPCMapper::Adapters; end
2
2
 
3
3
  require 'rpc_mapper/adapters/abstract_adapter'
4
4
  require 'rpc_mapper/adapters/bertrpc_adapter'
5
+ require 'rpc_mapper/adapters/restful_http_adapter'
@@ -40,7 +40,7 @@ module RPCMapper::Associations
40
40
  when :belongs, :one
41
41
  klass.first(query_options) if query_options[:conditions] # TRP: Only run query if conditions is not nil
42
42
  when :many
43
- klass.all(query_options) if query_options[:conditions] # TRP: Only run query if conditions is not nil
43
+ klass.apply_finder_options(query_options) if query_options[:conditions] # TRP: Only apply scopes if conditions is not nil
44
44
  end
45
45
  instance_variable_set(cache_ivar, cached_value)
46
46
  end
@@ -1,24 +1,5 @@
1
- # TRP: Cherry pick some goodies from active_support
2
- require 'active_support/core_ext/array'
3
- begin
4
- require 'active_support/core_ext/duplicable' #ActiveSupport 2.3.5
5
- rescue LoadError => exception
6
- require 'active_support/core_ext/object/duplicable' #ActiveSupport 3.0.0.RC
7
- end
8
- require 'active_support/core_ext/class/inheritable_attributes'
9
- require 'active_support/core_ext/hash/deep_merge'
10
- require 'active_support/core_ext/module/delegation'
11
- Hash.send(:include, ActiveSupport::CoreExtensions::Hash::DeepMerge) unless Hash.new.respond_to?(:deep_merge)
12
-
13
- # TRP: Used for pretty logging
14
- require 'benchmark'
15
-
16
- # TRP: RPCMapper core_ext
17
- require 'rpc_mapper/core_ext/kernel/singleton_class'
18
-
19
1
  # TRP: RPCMapper modules
20
2
  require 'rpc_mapper/errors'
21
- require 'rpc_mapper/config_options'
22
3
  require 'rpc_mapper/associations/contains'
23
4
  require 'rpc_mapper/associations/external'
24
5
  require 'rpc_mapper/cacheable'
@@ -29,7 +10,6 @@ require 'rpc_mapper/adapters'
29
10
 
30
11
 
31
12
  class RPCMapper::Base
32
- include RPCMapper::ConfigOptions
33
13
  include RPCMapper::Associations::Contains
34
14
  include RPCMapper::Associations::External
35
15
  include RPCMapper::Serialization
@@ -38,23 +18,11 @@ class RPCMapper::Base
38
18
  attr_accessor :attributes, :new_record
39
19
  alias :new_record? :new_record
40
20
 
41
- class_inheritable_accessor :defined_attributes, :mutable, :cacheable, :scoped_methods, :declared_associations
42
- config_options :rpc_server_host => 'localhost',
43
- :rpc_server_port => 8000,
44
- :service => nil,
45
- :service_namespace => nil,
46
- :adapter_type => nil,
47
- # TRP: Only used if configure_mutable is called
48
- :mutable_default_parameters => {},
49
- :mutable_host => nil,
50
- # TRP: This is used to append any options to the call (e.g. value to authenticate the client with the server, :app_key)
51
- :default_options => {}
52
-
53
- self.mutable = false
21
+ class_inheritable_accessor :read_adapter, :write_adapter, :cacheable, :defined_attributes, :scoped_methods, :declared_associations
22
+
54
23
  self.cacheable = false
55
24
  self.declared_associations = {}
56
25
  self.defined_attributes = []
57
- @@adapter_pool = {}
58
26
 
59
27
  def initialize(attributes={})
60
28
  self.new_record = true
@@ -67,25 +35,25 @@ class RPCMapper::Base
67
35
 
68
36
  protected
69
37
 
70
- # TRP: Common interface for setting attributes to keep things consistent
71
- def set_attributes(attributes)
38
+ # TRP: Common interface for setting attributes to keep things consistent; if force is true the defined_attributes list will be ignored
39
+ def set_attributes(attributes, force=false)
72
40
  attributes = attributes.inject({}) do |options, (key, value)|
73
41
  options[key.to_s] = value
74
42
  options
75
43
  end
76
44
  @attributes = {} if @attributes.nil?
77
- @attributes.merge!(attributes.reject { |field, value| !self.defined_attributes.include?(field) })
45
+ @attributes.merge!(attributes.reject { |field, value| !self.defined_attributes.include?(field) && !force })
78
46
  end
79
47
 
80
- def set_attribute(attribute, value)
81
- set_attributes({ attribute => value })
48
+ def set_attribute(attribute, value, force=false)
49
+ set_attributes({ attribute => value }, force)
82
50
  end
83
51
 
84
52
  # Class Methods
85
53
  class << self
86
54
  public
87
55
 
88
- delegate :find, :first, :all, :search, :to => :scoped
56
+ delegate :find, :first, :all, :search, :apply_finder_options, :to => :scoped
89
57
  delegate :select, :group, :order, :joins, :where, :having, :limit, :offset, :from, :to => :scoped
90
58
 
91
59
  def new_from_data_store(hash)
@@ -121,40 +89,43 @@ class RPCMapper::Base
121
89
  protected
122
90
 
123
91
  def fetch_records(options={})
124
- self.adapter.call("#{self.service_namespace}__#{self.service}", options.merge(default_options)).collect { |hash| self.new_from_data_store(hash) }.compact
92
+ self.read_adapter.read(options).collect { |hash| self.new_from_data_store(hash) }.compact
125
93
  end
126
94
 
127
- def adapter
128
- @@adapter_pool[self.adapter_type] ||= RPCMapper::Adapters::AbstractAdapter.create(self.adapter_type, { :host => self.rpc_server_host, :port => self.rpc_server_port })
95
+ def read_with(adapter_type)
96
+ setup_adapter(:read, { :type => adapter_type })
129
97
  end
130
98
 
131
- def method_missing(method, *args, &block)
132
- if scoped.dynamic_finder_method(method)
133
- scoped.send(method, *args, &block)
99
+ def write_with(adapter_type)
100
+ if write_adapter
101
+ write_inheritable_attribute :write_adapter, nil if adapter_type != write_adapter.type
134
102
  else
135
- super
136
- end
137
- end
138
-
139
- def configure(options={})
140
- self.configure_options.each { |option| self.send("#{option}=", options[option]) if options[option] }
141
- end
142
-
143
- # TRP: Only pulls in mutable module if configure_mutable is called
144
- def configure_mutable(options={})
145
- unless mutable
146
- self.mutable = true
147
-
148
103
  # TRP: Pull in methods and libraries needed for mutable functionality
149
- require 'rpc_mapper/mutable'
150
- self.send(:include, RPCMapper::Mutable)
151
- self.save_mutable_configuration(options)
104
+ require 'rpc_mapper/persistence' unless defined?(RPCMapper::Persistence)
105
+ self.send(:include, RPCMapper::Persistence) unless self.class.ancestors.include?(RPCMapper::Persistence)
152
106
 
153
107
  # TRP: Create writers if attributes are declared before configure_mutable is called
154
108
  self.defined_attributes.each { |attribute| create_writer(attribute) }
155
109
  # TRP: Create serialized writers if attributes are declared serialized before this call
156
110
  self.serialized_attributes.each { |attribute| set_serialize_writers(attribute) }
157
111
  end
112
+ setup_adapter(:write, { :type => adapter_type })
113
+ end
114
+
115
+ def configure_read(&block)
116
+ configure_adapter(:read, &block)
117
+ end
118
+
119
+ def configure_write(&block)
120
+ configure_adapter(:write, &block)
121
+ end
122
+
123
+ def method_missing(method, *args, &block)
124
+ if scoped.dynamic_finder_method(method)
125
+ scoped.send(method, *args, &block)
126
+ else
127
+ super
128
+ end
158
129
  end
159
130
 
160
131
  def configure_cacheable(options={})
@@ -176,7 +147,7 @@ class RPCMapper::Base
176
147
  end
177
148
 
178
149
  # TRP: Setup the writers if mutable is set
179
- create_writer(attribute) if self.mutable
150
+ create_writer(attribute) if self.write_adapter
180
151
 
181
152
  end
182
153
  end
@@ -198,6 +169,28 @@ class RPCMapper::Base
198
169
  self.scoped_methods.last
199
170
  end
200
171
 
172
+ private
173
+
174
+ def setup_adapter(mode, config)
175
+ current_adapter = read_inheritable_attribute :"#{mode}_adapter"
176
+ type = config[:type] if config.is_a?(Hash)
177
+
178
+ new_adapter = if current_adapter
179
+ current_adapter.extend_adapter(config)
180
+ else
181
+ RPCMapper::Adapters::AbstractAdapter.create(type, config)
182
+ end
183
+
184
+ write_inheritable_attribute :"#{mode}_adapter", new_adapter
185
+ end
186
+
187
+ def configure_adapter(mode, &block)
188
+ raise ArgumentError, "A block must be passed to configure_#{mode} method." unless block_given?
189
+ raise ArgumentError, "You must first define an adapter before configuring it. Use #{mode}_with :adapter_type." unless self.send(:"#{mode}_adapter")
190
+
191
+ setup_adapter(mode, block)
192
+ end
193
+
201
194
  end
202
195
 
203
196
  end
@@ -16,7 +16,7 @@ module RPCMapper::Cacheable
16
16
  cache_hit = self.cacheable.read(key)
17
17
 
18
18
  if cache_hit
19
- self.adapter.log(options, "CACHE #{self.service_namespace}__#{self.service}")
19
+ self.read_adapter.log(options, "CACHE")
20
20
  cache_hit.each { |fv| fv.fresh = false.freeze }
21
21
  cache_hit
22
22
  else
@@ -0,0 +1,47 @@
1
+ module RPCMapper::Persistence
2
+
3
+ module ClassMethods
4
+
5
+ protected
6
+
7
+ def create_writer(attribute)
8
+ define_method("#{attribute}=") do |value|
9
+ self[attribute] = value
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+
16
+ module InstanceMethods
17
+
18
+ def []=(attribute, value)
19
+ set_attribute(attribute, value)
20
+ end
21
+
22
+ def attributes=(attributes)
23
+ set_attributes(attributes)
24
+ end
25
+
26
+ def save
27
+ write_adapter.write(self)
28
+ end
29
+
30
+ def update_attributes(attributes)
31
+ self.attributes = attributes
32
+ save
33
+ end
34
+
35
+ def destroy
36
+ write_adapter.delete(self)
37
+ end
38
+ alias :delete :destroy
39
+
40
+ end
41
+
42
+ def self.included(receiver)
43
+ receiver.extend ClassMethods
44
+ receiver.send :include, InstanceMethods
45
+ end
46
+
47
+ end
@@ -15,7 +15,7 @@ module RPCMapper::Serialization
15
15
  alias_method "#{field}_raw", field
16
16
  alias_method field, "deserialize_#{field}"
17
17
 
18
- set_serialize_writers(field) if self.mutable
18
+ set_serialize_writers(field) if self.write_adapter
19
19
 
20
20
  end
21
21
  end
@@ -2,8 +2,8 @@ module RPCMapper
2
2
  module Version
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 0
6
- TINY = 2
5
+ MINOR = 1
6
+ TINY = 0
7
7
 
8
8
  def self.to_s # :nodoc:
9
9
  [MAJOR, MINOR, TINY].join('.')
data/lib/rpc_mapper.rb CHANGED
@@ -1,5 +1,22 @@
1
- require 'bert'
2
- require 'bertrpc'
1
+ # TRP: Cherry pick some goodies from active_support
2
+ require 'active_support/core_ext/array'
3
+ require 'active_support/core_ext/class/inheritable_attributes'
4
+ require 'active_support/core_ext/hash/deep_merge'
5
+ begin
6
+ require 'active_support/core_ext/duplicable' #ActiveSupport 2.3.x
7
+ Hash.send(:include, ActiveSupport::CoreExtensions::Hash::DeepMerge) unless Hash.instance_methods.include?('deep_merge')
8
+ rescue LoadError => exception
9
+ require 'active_support/core_ext/object/duplicable' #ActiveSupport 3.0.x
10
+ end
11
+ require 'active_support/core_ext/module/delegation'
12
+
13
+ # TRP: Used for pretty logging
14
+ autoload :Benchmark, 'benchmark'
15
+
16
+ require 'ostruct'
17
+
18
+ # TRP: RPCMapper core_ext
19
+ require 'rpc_mapper/core_ext/kernel/singleton_class'
3
20
 
4
21
  module RPCMapper
5
22
  @@log_file = nil
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 2
10
- version: 0.0.2
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Travis Petticrew
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-03 00:00:00 -05:00
18
+ date: 2010-10-26 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -125,6 +125,7 @@ files:
125
125
  - Rakefile
126
126
  - lib/rpc_mapper/adapters/abstract_adapter.rb
127
127
  - lib/rpc_mapper/adapters/bertrpc_adapter.rb
128
+ - lib/rpc_mapper/adapters/restful_http_adapter.rb
128
129
  - lib/rpc_mapper/adapters.rb
129
130
  - lib/rpc_mapper/associations/common.rb
130
131
  - lib/rpc_mapper/associations/contains.rb
@@ -133,11 +134,10 @@ files:
133
134
  - lib/rpc_mapper/cacheable/entry.rb
134
135
  - lib/rpc_mapper/cacheable/store.rb
135
136
  - lib/rpc_mapper/cacheable.rb
136
- - lib/rpc_mapper/config_options.rb
137
137
  - lib/rpc_mapper/core_ext/kernel/singleton_class.rb
138
138
  - lib/rpc_mapper/errors.rb
139
139
  - lib/rpc_mapper/logger.rb
140
- - lib/rpc_mapper/mutable.rb
140
+ - lib/rpc_mapper/persistence.rb
141
141
  - lib/rpc_mapper/relation/finder_methods.rb
142
142
  - lib/rpc_mapper/relation/query_methods.rb
143
143
  - lib/rpc_mapper/relation.rb
@@ -1,41 +0,0 @@
1
- module RPCMapper
2
-
3
- module ConfigOptions
4
- module ClassMethods
5
-
6
- def config_options(options={})
7
- options.each do |option, default_value|
8
- class_eval do
9
- self.configure_options << option
10
- class_inheritable_accessor option
11
- self.send "#{option}=", default_value
12
- end
13
- # TRP: We run a direct string eval on the class because we cannot get a closure on the class << self scope
14
- # We need that in order to use our option variable to define a class method of the same name.
15
- self.class_eval <<-EOS
16
- def self.#{option} # def self.my_awesome_option
17
- val = read_inheritable_attribute(:#{option}) # val = read_inheritable_attribute(:my_awesome_option)
18
- val.is_a?(Proc) ? write_inheritable_attribute(:#{option}, val.call) : val # val.is_a?(Proc) ? write_inheritable_attribute(:my_awesome_option, val.call) : val
19
- end # end
20
- EOS
21
- end
22
- end
23
-
24
- end
25
-
26
- module InstanceMethods
27
-
28
- end
29
-
30
- def self.included(receiver)
31
- receiver.class_eval do
32
- class_inheritable_accessor :configure_options
33
- self.configure_options = []
34
- end
35
-
36
- receiver.extend ClassMethods
37
- receiver.send :include, InstanceMethods
38
- end
39
- end
40
-
41
- end
@@ -1,138 +0,0 @@
1
- require 'net/http'
2
- require 'uri'
3
-
4
- module RPCMapper
5
-
6
- module Mutable
7
-
8
- module ClassMethods
9
-
10
- protected
11
-
12
- def save_mutable_configuration(options={})
13
- self.mutable_service = options[:service] || self.service
14
- self.mutable_post_body_wrapper = options[:post_body_wrapper]
15
- end
16
-
17
- def create_writer(attribute)
18
- define_method("#{attribute}=") do |value|
19
- self[attribute] = value
20
- end
21
- end
22
-
23
- end
24
-
25
-
26
- module InstanceMethods
27
-
28
- def []=(attribute, value)
29
- set_attribute(attribute, value)
30
- end
31
-
32
- def attributes=(attributes)
33
- set_attributes(attributes)
34
- end
35
-
36
- def save
37
- new_record? ? post_http(build_params_from_attributes) : put_http(build_params_from_attributes)
38
- end
39
-
40
- def update_attributes(attributes)
41
- self.attributes = attributes
42
- save
43
- end
44
-
45
- def destroy
46
- delete_http
47
- end
48
- alias :delete :destroy
49
-
50
-
51
- protected
52
-
53
-
54
- def post_http(params)
55
- http_call(:post, params)
56
- end
57
-
58
- def put_http(params)
59
- http_call(:put, params)
60
- end
61
-
62
- def delete_http
63
- http_call(:delete, self.mutable_default_parameters)
64
- end
65
-
66
- def http_call(method, params={})
67
- request_klass = case method
68
- when :post then Net::HTTP::Post
69
- when :put then Net::HTTP::Put
70
- when :delete then Net::HTTP::Delete
71
- end
72
-
73
- req_url = self.build_url(method)
74
-
75
- request = if method == :delete
76
- request = request_klass.new([req_url.path, req_url.query].join('?'))
77
- else
78
- request = request_klass.new(req_url.path)
79
- request.set_form_data(params) unless method == :delete
80
- request
81
- end
82
-
83
- self.class.send(:adapter).log(params, "#{method.to_s.upcase} #{req_url}") do
84
- @response = Net::HTTP.new(req_url.host, req_url.port).start { |http| http.request(request) }
85
- end
86
- parse_response_code(@response)
87
- end
88
-
89
- def parse_response_code(response)
90
- case response
91
- when Net::HTTPSuccess, Net::HTTPRedirection
92
- true
93
- else
94
- false
95
- end
96
- end
97
-
98
- def build_params_from_attributes
99
- if self.mutable_post_body_wrapper
100
- params = self.mutable_default_parameters
101
- @attributes.each do |attribute, value|
102
- params.merge!({"#{self.mutable_post_body_wrapper}[#{attribute}]" => value})
103
- end
104
- # TRP: Append ivar mutable_params to params if set
105
- params.merge!(self.mutable_params) if self.mutable_params.is_a?(Hash)
106
-
107
- params
108
- else
109
- @attributes
110
- end
111
- end
112
-
113
- def build_url(method)
114
- url = [self.mutable_host.gsub(%r{/$}, ''), self.mutable_service]
115
- url << self.id unless self.new_record?
116
- uri = URI.parse "#{url.join('/')}.json"
117
-
118
- if method == :delete
119
- uri.query = self.mutable_default_parameters.collect { |key, value| "#{key}=#{value}" }.join('&')
120
- end
121
-
122
- uri
123
- end
124
-
125
- end
126
-
127
- def self.included(receiver)
128
- receiver.class_inheritable_accessor :mutable_service, :mutable_post_body_wrapper
129
- receiver.send :attr_accessor, :mutable_params
130
- receiver.send(:attr_accessor, :response)
131
-
132
- receiver.extend ClassMethods
133
- receiver.send :include, InstanceMethods
134
- end
135
-
136
- end
137
-
138
- end