axel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +21 -0
- data/.octopolo.yml +2 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +271 -0
- data/Rakefile +13 -0
- data/app/models/axel/api_proxy.rb +86 -0
- data/app/models/axel/associations/base.rb +64 -0
- data/app/models/axel/associations/belongs_to.rb +43 -0
- data/app/models/axel/associations/has_many.rb +29 -0
- data/app/models/axel/associations/has_one.rb +30 -0
- data/app/models/axel/payload.rb +4 -0
- data/app/models/axel/payload/base.rb +107 -0
- data/app/models/axel/payload/errors.rb +62 -0
- data/app/models/axel/payload/metadata.rb +57 -0
- data/app/models/axel/querier.rb +166 -0
- data/app/models/axel/router.rb +119 -0
- data/app/models/axel/service_resource.rb +4 -0
- data/app/models/axel/service_resource/associations.rb +80 -0
- data/app/models/axel/service_resource/attributes.rb +23 -0
- data/app/models/axel/service_resource/automatic_resource.rb +23 -0
- data/app/models/axel/service_resource/base.rb +47 -0
- data/app/models/axel/service_resource/builder.rb +40 -0
- data/app/models/axel/service_resource/inspects.rb +17 -0
- data/app/models/axel/service_resource/payload_parser.rb +46 -0
- data/app/models/axel/service_resource/queries.rb +25 -0
- data/app/models/axel/service_resource/requesters.rb +49 -0
- data/app/models/axel/service_resource/routes.rb +19 -0
- data/app/models/axel/service_resource/typhoid_extensions.rb +134 -0
- data/app/views/axel/base/empty.json.erb +0 -0
- data/app/views/axel/base/empty.xml.builder +0 -0
- data/app/views/layouts/axel.json.jbuilder +7 -0
- data/app/views/layouts/axel.xml.builder +12 -0
- data/axel.gemspec +42 -0
- data/lib/axel.rb +56 -0
- data/lib/axel/application_extensions.rb +13 -0
- data/lib/axel/application_helper.rb +27 -0
- data/lib/axel/base_controller.rb +6 -0
- data/lib/axel/cascadable_attribute.rb +33 -0
- data/lib/axel/configurations/resource.rb +29 -0
- data/lib/axel/configurations/service.rb +28 -0
- data/lib/axel/configurator.rb +54 -0
- data/lib/axel/configurators/services.rb +29 -0
- data/lib/axel/controller_base.rb +27 -0
- data/lib/axel/controller_helpers.rb +209 -0
- data/lib/axel/controller_parameters.rb +32 -0
- data/lib/axel/engine.rb +14 -0
- data/lib/axel/inspector.rb +91 -0
- data/lib/axel/payload/remote_error.rb +14 -0
- data/lib/axel/request_options.rb +26 -0
- data/lib/axel/uri.rb +47 -0
- data/lib/axel/version.rb +3 -0
- data/lib/generators/axel/install_generator.rb +16 -0
- data/lib/generators/templates/README.md +22 -0
- data/lib/generators/templates/axel.rb +81 -0
- data/script/rails +5 -0
- data/spec/controllers/pages_controller_spec.rb +217 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/pages_controller.rb +6 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +62 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitignore +1 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/envelope_integration_check.rb +96 -0
- data/spec/helpers/axel/application_helper_spec.rb +31 -0
- data/spec/lib/axel/associations/base_spec.rb +28 -0
- data/spec/lib/axel/associations/belongs_to_spec.rb +62 -0
- data/spec/lib/axel/associations/has_many_spec.rb +23 -0
- data/spec/lib/axel/associations/has_one_spec.rb +23 -0
- data/spec/lib/axel/configurations/resource_spec.rb +15 -0
- data/spec/lib/axel/configurations/service_spec.rb +31 -0
- data/spec/lib/axel/configurator_spec.rb +26 -0
- data/spec/lib/axel/configurators/services_spec.rb +37 -0
- data/spec/lib/axel/controller_base_spec.rb +16 -0
- data/spec/lib/axel/controller_parameters_spec.rb +31 -0
- data/spec/lib/axel/inspector_spec.rb +45 -0
- data/spec/lib/axel/request_options_spec.rb +50 -0
- data/spec/lib/axel/uri_spec.rb +42 -0
- data/spec/lib/axel_spec.rb +64 -0
- data/spec/models/axel/api_proxy_spec.rb +66 -0
- data/spec/models/axel/payload/errors_spec.rb +165 -0
- data/spec/models/axel/payload/metadata_spec.rb +141 -0
- data/spec/models/axel/querier_spec.rb +158 -0
- data/spec/models/axel/router_spec.rb +115 -0
- data/spec/models/axel/service_resource/base_spec.rb +244 -0
- data/spec/models/axel/service_resource/builder_spec.rb +64 -0
- data/spec/models/axel/service_resource/payload_parser_spec.rb +60 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/address.rb +5 -0
- data/spec/support/persona.rb +15 -0
- data/spec/support/user.rb +6 -0
- data/spec/views/axel/base/empty_spec.rb +34 -0
- metadata +508 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
module Axel
|
2
|
+
module Associations
|
3
|
+
class Base
|
4
|
+
attr_accessor :model
|
5
|
+
attr_accessor :relation_name
|
6
|
+
attr_accessor :options
|
7
|
+
|
8
|
+
def initialize(model, relation_name, options)
|
9
|
+
self.model = model
|
10
|
+
self.relation_name = relation_name.to_s
|
11
|
+
self.options = options || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def handles_method?(method_name)
|
15
|
+
matchers.any? { |matcher| method_name.to_s.match(matcher) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_method(instance, method_name, *args, &block)
|
19
|
+
if included?
|
20
|
+
included_getter(instance, *args, &block)
|
21
|
+
else
|
22
|
+
method_chooser(method_name)[instance, *args, &block]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def included?
|
29
|
+
!!options[:included]
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_klass
|
33
|
+
options[:class] || relation_name_klass
|
34
|
+
end
|
35
|
+
|
36
|
+
def premodule
|
37
|
+
model.name.split("::")[0..-2].join("::")
|
38
|
+
end
|
39
|
+
|
40
|
+
def relation_name_klass
|
41
|
+
"#{premodule}::#{relation_name.to_s.singularize.classify}".safe_constantize
|
42
|
+
end
|
43
|
+
|
44
|
+
def matcher_map
|
45
|
+
{
|
46
|
+
/\A#{relation_name}\z/ => :getter
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def matchers
|
51
|
+
matcher_map.keys
|
52
|
+
end
|
53
|
+
|
54
|
+
def method_chooser(method_name)
|
55
|
+
name = matcher_map[matchers.find { |matcher| method_name.to_s.match matcher }]
|
56
|
+
if name
|
57
|
+
method(name)
|
58
|
+
else
|
59
|
+
raise NoMethodError, "Could not find an association method for `#{method_name}'"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Axel
|
2
|
+
module Associations
|
3
|
+
class BelongsTo < Base
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def included_getter(instance, *args, &block)
|
8
|
+
relation_attributes = (instance.try(:attributes) || {})[relation_name]
|
9
|
+
build_klass.new(relation_attributes) if relation_attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_nested?
|
13
|
+
!!options[:find_nested]
|
14
|
+
end
|
15
|
+
|
16
|
+
def getter(instance, *args, &block)
|
17
|
+
request_options = args.extract_options!
|
18
|
+
if find_nested?
|
19
|
+
build_klass
|
20
|
+
.querier
|
21
|
+
.without_default_path
|
22
|
+
.at_path(route_path(instance))
|
23
|
+
.request_options(request_options)
|
24
|
+
.first
|
25
|
+
else
|
26
|
+
build_klass.find(instance.public_send(association_id_method), request_options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def route_path(instance)
|
31
|
+
[URI(instance.request_uri).path, association_path(instance)].join("/")
|
32
|
+
end
|
33
|
+
|
34
|
+
def association_path(instance) # needs to be belongs_to, some looks has_many
|
35
|
+
"#{relation_name.to_s.pluralize}/#{instance.public_send(association_id_method)}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def association_id_method
|
39
|
+
options[:id_attribute] || "#{relation_name.to_s.singularize.underscore}_id"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Axel
|
2
|
+
module Associations
|
3
|
+
class HasMany < Base
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def included_getter(instance, *args, &block)
|
8
|
+
Array(instance.attributes[relation_name]).map { |attributes| build_klass.new(attributes) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def getter(instance, *args, &block)
|
12
|
+
request_options = args.extract_options!
|
13
|
+
build_klass
|
14
|
+
.querier
|
15
|
+
.without_default_path
|
16
|
+
.at_path(route_path(instance))
|
17
|
+
.request_options request_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def route_path(instance)
|
21
|
+
[URI(instance.request_uri).path, association_path].join("/")
|
22
|
+
end
|
23
|
+
|
24
|
+
def association_path # needs to be belongs_to, some looks has_many
|
25
|
+
options[:suffix_path].present? && options[:suffix_path] || relation_name.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Axel
|
2
|
+
module Associations
|
3
|
+
class HasOne < Base
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def included_getter(instance, *args, &block)
|
8
|
+
Array(instance.attributes[relation_name]).map { |attributes| build_klass.new(attributes) }.first
|
9
|
+
end
|
10
|
+
|
11
|
+
def getter(instance, *args, &block)
|
12
|
+
request_options = args.extract_options!
|
13
|
+
build_klass
|
14
|
+
.querier
|
15
|
+
.without_default_path
|
16
|
+
.at_path(route_path(instance))
|
17
|
+
.request_options(request_options)
|
18
|
+
.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def route_path(instance)
|
22
|
+
[URI(instance.request_uri).path, association_path].join("/")
|
23
|
+
end
|
24
|
+
|
25
|
+
def association_path # needs to be belongs_to, some looks has_many
|
26
|
+
options[:suffix_path].present? && options[:suffix_path] || relation_name.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Axel
|
2
|
+
module Payload
|
3
|
+
class Base
|
4
|
+
attr_reader :attributes
|
5
|
+
|
6
|
+
delegate :fetch, to: :attributes
|
7
|
+
|
8
|
+
def self.root_node(name = nil)
|
9
|
+
@root_node = name if name
|
10
|
+
@root_node
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.attribute(name, options = {})
|
14
|
+
attribute_defaults[name.to_s.to_sym] = options[:default]
|
15
|
+
visibility_read = options.has_key?(:read) ? options[:read] : true
|
16
|
+
visibility_write = options.has_key?(:write) ? options[:write] : true
|
17
|
+
if visibility_read
|
18
|
+
define_method name do
|
19
|
+
@attributes[name]
|
20
|
+
end
|
21
|
+
if %w[public private protected].include? visibility_read.to_s
|
22
|
+
send visibility_read, name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if visibility_write
|
27
|
+
define_method "#{name}=" do |new_value|
|
28
|
+
@attributes[name] = new_value
|
29
|
+
end
|
30
|
+
if %w[public private protected].include? visibility_write.to_s
|
31
|
+
send visibility_write, name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.attribute_defaults
|
37
|
+
@attribute_defaults ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset!
|
41
|
+
@attributes = {}
|
42
|
+
apply_defaults
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(params = {})
|
47
|
+
apply_defaults
|
48
|
+
params = params.is_a?(Hash) ? params : {}
|
49
|
+
@attributes.merge! params
|
50
|
+
end
|
51
|
+
|
52
|
+
def []=(key, value)
|
53
|
+
@attributes[key] = decode(value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def [](key)
|
57
|
+
@attributes[key]
|
58
|
+
end
|
59
|
+
|
60
|
+
def display
|
61
|
+
drop? ? {} : @attributes
|
62
|
+
end
|
63
|
+
|
64
|
+
def display?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def drop?
|
69
|
+
!!@drop
|
70
|
+
end
|
71
|
+
|
72
|
+
def drop!
|
73
|
+
@drop = true
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_json
|
77
|
+
display? ? display.to_json : ""
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_xml
|
81
|
+
display? ? display.to_xml(dasherize: false, skip_instruct: true, root: self.class.root_node) : ""
|
82
|
+
end
|
83
|
+
|
84
|
+
def apply_defaults
|
85
|
+
@attributes = self.class.attribute_defaults.with_indifferent_access
|
86
|
+
end
|
87
|
+
private :apply_defaults
|
88
|
+
|
89
|
+
def decode(input)
|
90
|
+
if input.is_a? String
|
91
|
+
begin
|
92
|
+
ActiveSupport::JSON.decode input
|
93
|
+
rescue MultiJson::DecodeError, JSON::ParserError
|
94
|
+
begin
|
95
|
+
Hash.from_xml input
|
96
|
+
rescue REXML::ParseException
|
97
|
+
input
|
98
|
+
end
|
99
|
+
end
|
100
|
+
else
|
101
|
+
input
|
102
|
+
end
|
103
|
+
end
|
104
|
+
private :decode
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Axel
|
2
|
+
module Payload
|
3
|
+
class Errors < Base
|
4
|
+
root_node :error
|
5
|
+
attribute :messages, default: []
|
6
|
+
attribute :status, default: 200, read: :private
|
7
|
+
SUCCESS_CODES = [200, 201, 202, 204]
|
8
|
+
|
9
|
+
def initialize(params = {})
|
10
|
+
super
|
11
|
+
@suppress_response_codes = !!@attributes[:suppress_response_codes]
|
12
|
+
end
|
13
|
+
|
14
|
+
def exception
|
15
|
+
RemoteError.new(self) unless success?
|
16
|
+
end
|
17
|
+
|
18
|
+
def success?
|
19
|
+
SUCCESS_CODES.include?(status_code.to_i) && messages.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def messages=(messages)
|
23
|
+
@attributes[:messages] = [messages].flatten.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
def status=(status)
|
27
|
+
@attributes[:status] = status
|
28
|
+
end
|
29
|
+
|
30
|
+
def header_status
|
31
|
+
suppress_response_codes? ? 200 : status_code
|
32
|
+
end
|
33
|
+
|
34
|
+
def <<(message)
|
35
|
+
@attributes[:messages] << message
|
36
|
+
end
|
37
|
+
|
38
|
+
def display
|
39
|
+
drop? ? {} : { status: status_code, messages: messages }
|
40
|
+
end
|
41
|
+
|
42
|
+
def display?
|
43
|
+
!SUCCESS_CODES.include?(status_code.to_i) || messages.present?
|
44
|
+
end
|
45
|
+
|
46
|
+
def new_error(status, *messages)
|
47
|
+
self.status = status if status
|
48
|
+
self.messages = self.messages + messages
|
49
|
+
end
|
50
|
+
|
51
|
+
def status_code
|
52
|
+
status ? Rack::Utils.status_code(status) : 200
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def suppress_response_codes?
|
58
|
+
@suppress_response_codes
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Axel
|
2
|
+
module Payload
|
3
|
+
class Metadata < Base
|
4
|
+
root_node :metadata
|
5
|
+
|
6
|
+
def paged?
|
7
|
+
total_pages > 1
|
8
|
+
end
|
9
|
+
|
10
|
+
def total_pages
|
11
|
+
raw = pagination_settings["total_pages"].to_i
|
12
|
+
raw == 0 ? 1 : raw
|
13
|
+
end
|
14
|
+
|
15
|
+
def merge!(other_object)
|
16
|
+
tap do
|
17
|
+
@attributes.merge! mergeable_from(other_object)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def merge(other_object)
|
22
|
+
#self.class.new(attributes).tap do |c|
|
23
|
+
dup.tap do |c|
|
24
|
+
c.merge!(mergeable_from(other_object))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def dup(*args)
|
29
|
+
super.tap do |d|
|
30
|
+
d.instance_variable_set "@attributes", @attributes.clone
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def clone(*args)
|
35
|
+
super.tap do |c|
|
36
|
+
c.instance_variable_set "@attributes", @attributes.clone
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def pagination_settings
|
41
|
+
fetch("pagination", {})
|
42
|
+
end
|
43
|
+
private :pagination_settings
|
44
|
+
|
45
|
+
def mergeable_from(object)
|
46
|
+
if object.respond_to?(:attributes) && object.attributes.is_a?(Hash)
|
47
|
+
object.attributes
|
48
|
+
elsif object.is_a? Hash
|
49
|
+
object
|
50
|
+
else
|
51
|
+
{} # unmergeable, should think about erroring
|
52
|
+
end
|
53
|
+
end
|
54
|
+
private :mergeable_from
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Axel
|
2
|
+
class Querier
|
3
|
+
private
|
4
|
+
attr_writer :klass
|
5
|
+
attr_writer :loaded
|
6
|
+
attr_reader :records
|
7
|
+
|
8
|
+
protected
|
9
|
+
attr_accessor :where_values
|
10
|
+
attr_accessor :manual_uri
|
11
|
+
attr_accessor :extra_paths
|
12
|
+
attr_accessor :request_option_values
|
13
|
+
attr_accessor :paged
|
14
|
+
attr_writer :records
|
15
|
+
|
16
|
+
public
|
17
|
+
attr_reader :klass
|
18
|
+
attr_reader :loaded
|
19
|
+
|
20
|
+
alias loaded? loaded
|
21
|
+
alias paged? paged
|
22
|
+
|
23
|
+
def self.query_methods
|
24
|
+
[
|
25
|
+
:all,
|
26
|
+
:none,
|
27
|
+
:where,
|
28
|
+
:uri,
|
29
|
+
:to_a,
|
30
|
+
:at_path,
|
31
|
+
:request_options,
|
32
|
+
:without_default_path,
|
33
|
+
:paged
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(klass)
|
38
|
+
self.klass = klass
|
39
|
+
self.records = []
|
40
|
+
self.extra_paths = []
|
41
|
+
self.loaded = false
|
42
|
+
self.where_values = {}.with_indifferent_access
|
43
|
+
self.request_option_values = {}.with_indifferent_access
|
44
|
+
end
|
45
|
+
|
46
|
+
def paged
|
47
|
+
query = clone
|
48
|
+
query.paged = true
|
49
|
+
query
|
50
|
+
end
|
51
|
+
|
52
|
+
def at_path(*paths)
|
53
|
+
return self if paths.blank?
|
54
|
+
query = clone
|
55
|
+
query.extra_paths += paths
|
56
|
+
query
|
57
|
+
end
|
58
|
+
|
59
|
+
# "http://user-service.dev"
|
60
|
+
def uri(base_url)
|
61
|
+
return self if base_url.blank?
|
62
|
+
query = clone
|
63
|
+
query.manual_uri = base_url.to_s
|
64
|
+
query
|
65
|
+
end
|
66
|
+
|
67
|
+
def where(params = {})
|
68
|
+
return self if params.blank? || !params.is_a?(Hash)
|
69
|
+
query = clone
|
70
|
+
query.request_option_values.deep_merge! params: params
|
71
|
+
query
|
72
|
+
end
|
73
|
+
|
74
|
+
def request_options(params = {})
|
75
|
+
return self if params.blank? || !params.is_a?(Hash)
|
76
|
+
query = clone
|
77
|
+
query.request_option_values.deep_merge! params
|
78
|
+
query
|
79
|
+
end
|
80
|
+
alias_method :all, :request_options
|
81
|
+
|
82
|
+
def none
|
83
|
+
query = clone
|
84
|
+
query.loaded!
|
85
|
+
query.records = []
|
86
|
+
query
|
87
|
+
end
|
88
|
+
|
89
|
+
def without_default_path
|
90
|
+
query = clone
|
91
|
+
query.manual_uri = klass.site
|
92
|
+
query
|
93
|
+
end
|
94
|
+
|
95
|
+
def reload
|
96
|
+
reset
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_a
|
101
|
+
Array(loaded? ? records : self.records = run_requests)
|
102
|
+
end
|
103
|
+
|
104
|
+
def inspect
|
105
|
+
to_a.inspect
|
106
|
+
end
|
107
|
+
|
108
|
+
def loaded!
|
109
|
+
self.loaded = true
|
110
|
+
end
|
111
|
+
protected :loaded!
|
112
|
+
|
113
|
+
def reset
|
114
|
+
self.loaded = false
|
115
|
+
self.records = []
|
116
|
+
self
|
117
|
+
end
|
118
|
+
private :reset
|
119
|
+
|
120
|
+
def request_uri
|
121
|
+
Uri.new((manual_uri || klass.request_uri), *extra_paths).to_s
|
122
|
+
end
|
123
|
+
private :request_uri
|
124
|
+
|
125
|
+
def retrieve_request_options
|
126
|
+
klass.retrieve_default_request_options request_option_values
|
127
|
+
end
|
128
|
+
private :retrieve_request_options
|
129
|
+
|
130
|
+
def run_requests
|
131
|
+
loaded!
|
132
|
+
execute_request_on_klass
|
133
|
+
end
|
134
|
+
private :run_requests
|
135
|
+
|
136
|
+
def execute_request_on_klass
|
137
|
+
initial = klass.request(request_uri, retrieve_request_options)
|
138
|
+
return initial unless paged?
|
139
|
+
|
140
|
+
single = initial.first
|
141
|
+
return initial if single.blank? || !single.paged?
|
142
|
+
|
143
|
+
(2..single.total_pages).reduce(initial) do |memo, page|
|
144
|
+
paged_options = retrieve_request_options
|
145
|
+
.stringify_keys
|
146
|
+
.deep_merge "params" => { "page" => page }
|
147
|
+
memo + klass.request(request_uri, paged_options)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
private :execute_request_on_klass
|
151
|
+
|
152
|
+
def respond_to?(method, include_private = false)
|
153
|
+
super || Array.public_method_defined?(method) || klass.routes.has_key?(method)
|
154
|
+
end
|
155
|
+
|
156
|
+
def method_missing(method, *args, &block)
|
157
|
+
if Array.method_defined?(method)
|
158
|
+
to_a.public_send(method, *args, &block)
|
159
|
+
elsif klass.routes.has_key? method
|
160
|
+
klass.public_send method, *args
|
161
|
+
else
|
162
|
+
super
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|