restly 0.0.1.alpha.1 → 0.0.1.alpha.2
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/.rspec +2 -0
- data/README.md +63 -3
- data/lib/generators/restly_config_generator.rb +13 -0
- data/lib/generators/restly_model_generator.rb +18 -0
- data/lib/generators/templates/config.yml.erb +32 -0
- data/lib/generators/templates/model.rb.erb +9 -0
- data/lib/restly/associations/base.rb +83 -12
- data/lib/restly/associations/belongs_to.rb +23 -6
- data/lib/restly/associations/embeddable_resources/embeds_many.rb +4 -0
- data/lib/restly/associations/embeddable_resources/embeds_one.rb +4 -0
- data/lib/restly/associations/embeddable_resources.rb +15 -4
- data/lib/restly/associations/has_many.rb +0 -9
- data/lib/restly/associations/has_one.rb +0 -9
- data/lib/restly/associations.rb +75 -15
- data/lib/restly/base/generic_methods.rb +10 -2
- data/lib/restly/base/includes.rb +0 -22
- data/lib/restly/base/instance/attributes.rb +26 -16
- data/lib/restly/base/instance/persistence.rb +6 -1
- data/lib/restly/base/{write_callbacks.rb → instance/write_callbacks.rb} +1 -1
- data/lib/restly/base/instance.rb +15 -9
- data/lib/restly/base.rb +3 -4
- data/lib/restly/client.rb +2 -2
- data/lib/restly/collection/pagination.rb +1 -1
- data/lib/restly/concerned_inheritance.rb +30 -0
- data/lib/restly/configuration.rb +20 -18
- data/lib/restly/error.rb +18 -20
- data/lib/restly/nested_attributes.rb +4 -3
- data/lib/restly/proxies/{auth.rb → authorization.rb} +1 -1
- data/lib/restly/proxies/base.rb +4 -0
- data/lib/restly/proxies/{params.rb → with_params.rb} +1 -1
- data/lib/restly/proxies/with_path.rb +24 -0
- data/lib/restly/proxies.rb +3 -4
- data/lib/restly/railtie.rb +5 -0
- data/lib/restly/version.rb +1 -1
- data/lib/restly.rb +2 -0
- data/restly.gemspec +0 -1
- data/spec/restly/associations/base_spec.rb +8 -0
- data/spec/restly/associations/belongs_to_spec.rb +8 -0
- data/spec/restly/associations/embeddable_resources/embeds_many_spec.rb +8 -0
- data/spec/restly/associations/embeddable_resources/embeds_one_spec.rb +8 -0
- data/spec/restly/associations/embeddable_resources_spec.rb +8 -0
- data/spec/restly/associations/has_many_spec.rb +8 -0
- data/spec/restly/associations/has_one_spec.rb +8 -0
- data/spec/restly/associations_spec.rb +8 -0
- data/spec/restly/base/fields_spec.rb +8 -0
- data/spec/restly/base/generic_methods_spec.rb +8 -0
- data/spec/restly/base/includes_spec.rb +8 -0
- data/spec/restly/base/instance/actions_spec.rb +8 -0
- data/spec/restly/base/instance/attributes_spec.rb +8 -0
- data/spec/restly/base/instance/persistence_spec.rb +8 -0
- data/spec/restly/base/instance/write_callbacks_spec.rb +8 -0
- data/spec/restly/base/instance_spec.rb +8 -0
- data/spec/restly/base/mass_assignment_security_spec.rb +8 -0
- data/spec/restly/base/resource/finders_spec.rb +8 -0
- data/spec/restly/base/resource_spec.rb +8 -0
- data/spec/restly/base_spec.rb +5 -51
- data/spec/restly/client_spec.rb +8 -0
- data/spec/restly/collection/pagination_spec.rb +8 -0
- data/spec/restly/collection_spec.rb +8 -0
- data/spec/restly/concearned_inheritance_spec.rb +8 -0
- data/spec/restly/configuration_spec.rb +8 -0
- data/spec/restly/connection_spec.rb +8 -0
- data/spec/restly/controller_methods_spec.rb +8 -0
- data/spec/restly/middleware_spec.rb +8 -0
- data/spec/restly/nested_attributes_spec.rb +8 -0
- data/spec/restly/proxies/associations/collection_spec.rb +8 -0
- data/spec/restly/proxies/associations/instance_spec.rb +8 -0
- data/spec/restly/proxies/authorization_spec.rb +8 -0
- data/spec/restly/proxies/base_spec.rb +8 -0
- data/spec/restly/proxies/with_params_spec.rb +8 -0
- data/spec/restly/thread_local_spec.rb +8 -0
- data/spec/{helper.rb → spec_helper.rb} +0 -3
- metadata +82 -26
- data/lib/restly/associations/builder.rb +0 -30
- data/spec/fakewebs.rb +0 -0
@@ -12,26 +12,34 @@ module Restly::Base::Instance::Attributes
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def attributes
|
15
|
-
|
16
|
-
hash[key] =
|
15
|
+
fields.reduce(HashWithIndifferentAccess.new) do |hash, key|
|
16
|
+
hash[key] = read_attribute key, autoload: false
|
17
17
|
hash
|
18
18
|
end
|
19
|
-
@attributes.reverse_merge!(nil_values)
|
20
19
|
end
|
21
20
|
|
22
21
|
def write_attribute(attr, val)
|
23
22
|
if fields.include?(attr)
|
24
23
|
send("#{attr}_will_change!".to_sym) unless val == @attributes[attr.to_sym] || !@loaded
|
25
24
|
@attributes[attr.to_sym] = val
|
25
|
+
|
26
|
+
elsif (association = klass.reflect_on_resource_association attr).present?
|
27
|
+
set_association attr, association.stub(self, val) unless (@association_attributes ||= {}.with_indifferent_access)[attr].present?
|
28
|
+
|
26
29
|
else
|
27
30
|
puts "WARNING: Attribute `#{attr}` not written. ".colorize(:yellow) +
|
28
31
|
"To fix this add the following the the model. -- field :#{attr}"
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
32
|
-
def read_attribute(attr)
|
33
|
-
|
34
|
-
attributes[attr.to_sym]
|
35
|
+
def read_attribute(attr, options={})
|
36
|
+
options.reverse_merge!({autoload: true})
|
37
|
+
if @attributes[attr.to_sym].nil? && !!options[:autoload] && !loaded?
|
38
|
+
load!
|
39
|
+
read_attribute(attr)
|
40
|
+
else
|
41
|
+
@attributes[attr.to_sym]
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
45
|
alias :attribute :read_attribute
|
@@ -51,10 +59,18 @@ module Restly::Base::Instance::Attributes
|
|
51
59
|
attribute(attr)
|
52
60
|
end
|
53
61
|
|
62
|
+
def respond_to_attribute?(m)
|
63
|
+
!!(/(?<attr>\w+)(?<setter>=)?$/ =~ m.to_s) && associations.include?(attr)
|
64
|
+
end
|
65
|
+
|
66
|
+
def respond_to?(m, include_private = false)
|
67
|
+
respond_to_attribute?(m) || super
|
68
|
+
end
|
69
|
+
|
54
70
|
private
|
55
71
|
|
56
72
|
def attribute_for_inspect(attr_name)
|
57
|
-
value = attribute(attr_name)
|
73
|
+
value = attribute(attr_name, autoload: false)
|
58
74
|
if value.is_a?(String) && value.length > 50
|
59
75
|
"#{value[0..50]}...".inspect
|
60
76
|
else
|
@@ -63,26 +79,20 @@ module Restly::Base::Instance::Attributes
|
|
63
79
|
end
|
64
80
|
|
65
81
|
def set_attributes_from_response(response=self.response)
|
66
|
-
|
67
|
-
parsed = parsed[resource_name] if parsed.is_a?(Hash) && parsed[resource_name]
|
68
|
-
self.attributes = parsed
|
82
|
+
self.attributes = parsed_response(response)
|
69
83
|
end
|
70
84
|
|
71
85
|
def method_missing(m, *args, &block)
|
72
86
|
if !!(/(?<attr>\w+)(?<setter>=)?$/ =~ m.to_s) && fields.include?(m)
|
73
87
|
case !!setter
|
74
88
|
when true
|
75
|
-
write_attribute(
|
89
|
+
write_attribute(attr, *args)
|
76
90
|
when false
|
77
|
-
read_attribute(
|
91
|
+
read_attribute(attr)
|
78
92
|
end
|
79
93
|
else
|
80
94
|
super(m, *args, &block)
|
81
95
|
end
|
82
96
|
end
|
83
97
|
|
84
|
-
def respond_to_missing?(method_name, include_private = false)
|
85
|
-
!!(/(?<attr>\w+)=?$/ =~ method_name.to_s) && fields.include?(method_name)
|
86
|
-
end
|
87
|
-
|
88
98
|
end
|
@@ -14,7 +14,12 @@ module Restly::Base::Instance::Persistence
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def reload!
|
17
|
-
|
17
|
+
raise Restly::Error::MissingId, "Cannot reload #{resource_name}, either it hasn't been created or it is missing an ID." unless id
|
18
|
+
set_attributes_from_response connection.get(path, force: true)
|
19
|
+
@loaded = true
|
20
|
+
self
|
18
21
|
end
|
19
22
|
|
23
|
+
alias :load! :reload!
|
24
|
+
|
20
25
|
end
|
data/lib/restly/base/instance.rb
CHANGED
@@ -4,11 +4,13 @@ module Restly::Base::Instance
|
|
4
4
|
autoload :Actions
|
5
5
|
autoload :Attributes
|
6
6
|
autoload :Persistence
|
7
|
+
autoload :WriteCallbacks
|
7
8
|
|
8
9
|
include Restly::Base::GenericMethods
|
9
10
|
include Actions
|
10
11
|
include Attributes
|
11
12
|
include Persistence
|
13
|
+
include WriteCallbacks
|
12
14
|
|
13
15
|
included do
|
14
16
|
attr_reader :init_options, :response
|
@@ -43,8 +45,8 @@ module Restly::Base::Instance
|
|
43
45
|
|
44
46
|
end
|
45
47
|
|
46
|
-
def
|
47
|
-
|
48
|
+
def loaded?
|
49
|
+
@loaded
|
48
50
|
end
|
49
51
|
|
50
52
|
def set_response(response)
|
@@ -52,7 +54,16 @@ module Restly::Base::Instance
|
|
52
54
|
@response = response
|
53
55
|
if response.try(:body)
|
54
56
|
set_attributes_from_response
|
55
|
-
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def parsed_response(response=self.response)
|
61
|
+
return {} unless response
|
62
|
+
parsed = response.parsed || {}
|
63
|
+
if parsed.is_a?(Hash) && parsed[resource_name]
|
64
|
+
parsed[resource_name]
|
65
|
+
else
|
66
|
+
parsed
|
56
67
|
end
|
57
68
|
end
|
58
69
|
|
@@ -61,12 +72,7 @@ module Restly::Base::Instance
|
|
61
72
|
end
|
62
73
|
|
63
74
|
def connection=(val)
|
64
|
-
@connection
|
65
|
-
end
|
66
|
-
|
67
|
-
# Todo: Needed?
|
68
|
-
def instance
|
69
|
-
self
|
75
|
+
@connection = val
|
70
76
|
end
|
71
77
|
|
72
78
|
def klass
|
data/lib/restly/base.rb
CHANGED
@@ -2,13 +2,10 @@ module Restly
|
|
2
2
|
class Base
|
3
3
|
# Autoload
|
4
4
|
extend ActiveSupport::Autoload
|
5
|
-
#autoload :Pagination # Todo!
|
6
5
|
autoload :Resource
|
7
6
|
autoload :Instance
|
8
|
-
autoload :Collection
|
9
7
|
autoload :GenericMethods
|
10
8
|
autoload :Includes
|
11
|
-
autoload :WriteCallbacks
|
12
9
|
autoload :MassAssignmentSecurity
|
13
10
|
autoload :Fields
|
14
11
|
|
@@ -32,13 +29,15 @@ module Restly
|
|
32
29
|
# Set Up Callbacks
|
33
30
|
define_model_callbacks :create, :save, :delete, :update, :initialize
|
34
31
|
|
32
|
+
# Concerned Inheritance
|
33
|
+
include Restly::ConcernedInheritance
|
34
|
+
|
35
35
|
# Actions & Callbacks
|
36
36
|
extend Resource
|
37
37
|
include Includes
|
38
38
|
include Instance
|
39
39
|
include Fields
|
40
40
|
include MassAssignmentSecurity
|
41
|
-
include WriteCallbacks
|
42
41
|
|
43
42
|
# Relationships
|
44
43
|
include Restly::Associations
|
data/lib/restly/client.rb
CHANGED
@@ -5,8 +5,8 @@ class Restly::Client < OAuth2::Client
|
|
5
5
|
|
6
6
|
def initialize(*args, &block)
|
7
7
|
opts = args.extract_options!
|
8
|
-
self.id = args[0] || Restly::Configuration.client_id
|
9
|
-
self.secret = args[1] || Restly::Configuration.client_secret
|
8
|
+
self.id = args[0] || Restly::Configuration.oauth_options[:client_id]
|
9
|
+
self.secret = args[1] || Restly::Configuration.oauth_options[:client_secret]
|
10
10
|
self.site = opts.delete(:site) || Restly::Configuration.site
|
11
11
|
self.options = Restly::Configuration.client_options.merge(opts)
|
12
12
|
self.ssl = opts.delete(:ssl) || Restly::Configuration.ssl
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Restly::ConcernedInheritance
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
extend ClassMethods
|
6
|
+
|
7
|
+
class_attribute :inherited_callbacks
|
8
|
+
self.inherited_callbacks = []
|
9
|
+
|
10
|
+
inherited do
|
11
|
+
self.inherited_callbacks = inherited_callbacks
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def inherited(subclass = nil, &block)
|
21
|
+
self.inherited_callbacks << block and return if block_given?
|
22
|
+
|
23
|
+
inherited_callbacks.each do |call_block|
|
24
|
+
subclass.class_eval(&call_block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/restly/configuration.rb
CHANGED
@@ -4,30 +4,31 @@ module Restly::Configuration
|
|
4
4
|
defaults = {
|
5
5
|
session_key: :access_token,
|
6
6
|
load_middleware: true,
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
|
12
|
-
|
7
|
+
use_oauth: false,
|
8
|
+
cache: false,
|
9
|
+
default_format: :json,
|
10
|
+
oauth_options: {
|
11
|
+
:authorize_url => '/oauth/authorize',
|
12
|
+
:token_url => '/oauth/token',
|
13
|
+
:token_method => :post,
|
14
|
+
},
|
15
|
+
client_options: {
|
16
|
+
:connection_opts => {},
|
17
|
+
:max_redirects => 5,
|
18
|
+
:raise_errors => true
|
19
|
+
}
|
13
20
|
}
|
14
|
-
defaults.
|
21
|
+
config = defaults.deep_merge(@config || {})
|
22
|
+
config.assert_valid_keys(:session_key, :load_middleware, :oauth_options, :use_oauth, :cache, :cache_options, :client_options, :site, :default_format)
|
23
|
+
config
|
15
24
|
end
|
16
25
|
|
17
26
|
def self.client_options
|
18
|
-
config.
|
19
|
-
[ :authorize_url,
|
20
|
-
:token_url,
|
21
|
-
:token_method,
|
22
|
-
:connection_opts,
|
23
|
-
:max_redirects,
|
24
|
-
:raise_errors
|
25
|
-
].include?(k.to_sym)
|
26
|
-
end
|
27
|
+
config[:client_options].merge(config[:oauth_options])
|
27
28
|
end
|
28
29
|
|
29
30
|
def self.load_config(hash)
|
30
|
-
@config = hash
|
31
|
+
@config = hash.symbolize_keys
|
31
32
|
end
|
32
33
|
|
33
34
|
def self.method_missing(m, *args, &block)
|
@@ -38,6 +39,7 @@ module Restly::Configuration
|
|
38
39
|
true
|
39
40
|
end
|
40
41
|
|
41
|
-
|
42
|
+
config_file = File.join(Rails.root, 'config', 'restly.yml')
|
43
|
+
load_config YAML.load_file(config_file)[Rails.env] if defined?(Rails) && File.exists?(config_file)
|
42
44
|
|
43
45
|
end
|
data/lib/restly/error.rb
CHANGED
@@ -1,30 +1,28 @@
|
|
1
1
|
module Restly::Error
|
2
2
|
|
3
|
-
class
|
4
|
-
end
|
5
|
-
|
6
|
-
class RecordNotFound < StandardError
|
7
|
-
end
|
3
|
+
class StandardError < ::StandardError
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
class InvalidParentAssociation < StandardError
|
13
|
-
end
|
5
|
+
def message
|
6
|
+
super.red
|
7
|
+
end
|
14
8
|
|
15
|
-
class InvalidJoinerAssociation < StandardError
|
16
9
|
end
|
17
10
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
11
|
+
errors = %w{
|
12
|
+
RecordNotFound
|
13
|
+
WrongResourceType
|
14
|
+
InvalidParentAssociation
|
15
|
+
InvalidJoinerAssociation
|
16
|
+
InvalidObject
|
17
|
+
InvalidToken
|
18
|
+
InvalidConnection
|
19
|
+
MissingId
|
20
|
+
InvalidSpec
|
21
|
+
AssociationError
|
22
|
+
}
|
26
23
|
|
27
|
-
|
24
|
+
errors.each do |error|
|
25
|
+
const_set(error.to_sym, Class.new(StandardError))
|
28
26
|
end
|
29
27
|
|
30
28
|
end
|
@@ -15,8 +15,9 @@ module Restly::NestedAttributes
|
|
15
15
|
# One To One Association
|
16
16
|
def assign_nested_attributes_for_one_to_one_resource_association(association_name, attributes, assignment_opts = {})
|
17
17
|
options = self.nested_attributes_options[association_name]
|
18
|
-
association_attributes = attributes.delete("#{association_name}_attributes") || {}
|
19
|
-
associated_instance = send(association_name) ||
|
18
|
+
association_attributes[association_name] = attributes.delete("#{association_name}_attributes") || {}
|
19
|
+
associated_instance = send(association_name) ||
|
20
|
+
self.class.reflect_on_resource_association(association_name).build(self)
|
20
21
|
associated_instance.attributes = association_attributes
|
21
22
|
end
|
22
23
|
|
@@ -42,7 +43,7 @@ module Restly::NestedAttributes
|
|
42
43
|
attributes_collection.each do |attributes|
|
43
44
|
attributes = attributes.with_indifferent_access
|
44
45
|
if attributes[:id].blank?
|
45
|
-
send(association_name) << association.build(attributes.except(:id))
|
46
|
+
send(association_name) << association.build(self, attributes.except(:id))
|
46
47
|
elsif existing_record = existing_records.find{ |record| record.id.to_s == attributes['id'].to_s }
|
47
48
|
existing_record.attributes = attributes
|
48
49
|
end
|
data/lib/restly/proxies/base.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
class Restly::Proxies::WithPath < Restly::Proxies::Base
|
2
|
+
|
3
|
+
def initialize(receiver, *args)
|
4
|
+
super(receiver)
|
5
|
+
@options = args.extract_options!
|
6
|
+
@options.assert_valid_keys(:prepend, :append)
|
7
|
+
self.path = args.first
|
8
|
+
adjust_path_from_options! if @options.present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def adjust_path_from_options!
|
12
|
+
prepend = if @options[:prepend]
|
13
|
+
@options[:prepend].gsub(/^([^\/])/, "/\\1").gsub(/\/$/, "")
|
14
|
+
end
|
15
|
+
|
16
|
+
append = if @options[:append]
|
17
|
+
@options[:append].gsub(/^\//, "").gsub(/\/$/, "")
|
18
|
+
end
|
19
|
+
|
20
|
+
self.path = [prepend, path, append].compact.join('/')
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/restly/proxies.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module Restly::Proxies
|
2
2
|
extend ActiveSupport::Autoload
|
3
3
|
|
4
|
-
autoload :
|
5
|
-
autoload :
|
6
|
-
autoload :
|
7
|
-
autoload :Params
|
4
|
+
autoload :Authorization
|
5
|
+
autoload :WithParams
|
6
|
+
autoload :WithPath
|
8
7
|
autoload :Base
|
9
8
|
|
10
9
|
module Associations
|
data/lib/restly/railtie.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
module Restly
|
2
2
|
class Railtie < ::Rails::Railtie
|
3
3
|
|
4
|
+
generators do
|
5
|
+
require "generators/restly_model_generator"
|
6
|
+
require "generators/restly_config_generator"
|
7
|
+
end
|
8
|
+
|
4
9
|
initializer "my_engine.add_middleware" do |app|
|
5
10
|
app.middleware.use "Restly::Middleware" if Restly::Configuration.load_middleware
|
6
11
|
end
|
data/lib/restly/version.rb
CHANGED
data/lib/restly.rb
CHANGED
data/restly.gemspec
CHANGED