restly 0.0.1.alpha.1 → 0.0.1.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- 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