rpc-mapper 0.0.2 → 0.1.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.
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