restly 0.0.1.alpha.4 → 0.0.1.alpha.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/lib/restly/associations/base/builders.rb +27 -0
  2. data/lib/restly/associations/base/conditionals.rb +23 -0
  3. data/lib/restly/associations/base/loaders.rb +41 -0
  4. data/lib/restly/associations/base/modifiers.rb +24 -0
  5. data/lib/restly/associations/base/stubs.rb +21 -0
  6. data/lib/restly/associations/base.rb +13 -89
  7. data/lib/restly/associations/belongs_to.rb +2 -14
  8. data/lib/restly/associations/class_methods.rb +62 -0
  9. data/lib/restly/associations/has_one.rb +0 -4
  10. data/lib/restly/associations.rb +26 -83
  11. data/lib/restly/base/fields.rb +4 -0
  12. data/lib/restly/base/generic_methods.rb +1 -1
  13. data/lib/restly/base/instance/actions.rb +8 -5
  14. data/lib/restly/base/instance/attributes.rb +47 -14
  15. data/lib/restly/base/instance/persistence.rb +12 -1
  16. data/lib/restly/base/instance/write_callbacks.rb +9 -1
  17. data/lib/restly/base/instance.rb +28 -21
  18. data/lib/restly/base/resource/batch_actions.rb +15 -0
  19. data/lib/restly/base/resource/finders.rb +1 -1
  20. data/lib/restly/base/resource.rb +9 -0
  21. data/lib/restly/base.rb +9 -5
  22. data/lib/restly/collection.rb +46 -13
  23. data/lib/restly/configuration.rb +6 -4
  24. data/lib/restly/controller_methods.rb +5 -10
  25. data/lib/restly/embedded_associations/base.rb +7 -0
  26. data/lib/restly/{associations/embeddable_resources.rb → embedded_associations/class_methods.rb} +14 -5
  27. data/lib/restly/embedded_associations/embedded_in.rb +7 -0
  28. data/lib/restly/embedded_associations/embeds_many.rb +7 -0
  29. data/lib/restly/embedded_associations/embeds_one.rb +3 -0
  30. data/lib/restly/embedded_associations.rb +12 -0
  31. data/lib/restly/error.rb +1 -1
  32. data/lib/restly/nested_attributes.rb +2 -0
  33. data/lib/restly/proxies/associations/collection.rb +5 -4
  34. data/lib/restly/proxies/associations/instance.rb +2 -2
  35. data/lib/restly/proxies/base.rb +5 -0
  36. data/lib/restly/proxies/with_path.rb +2 -0
  37. data/lib/restly/version.rb +1 -1
  38. data/lib/restly.rb +2 -1
  39. data/spec/dummy/app/controllers/api/other_objects_controller.rb +45 -0
  40. data/spec/dummy/app/controllers/api/sample_objects_controller.rb +4 -4
  41. data/spec/dummy/app/models/other_object.rb +3 -0
  42. data/spec/dummy/app/models/sample_object.rb +2 -0
  43. data/spec/dummy/config/routes.rb +4 -1
  44. data/spec/restly/{associations/embeddable_resources → embeddable_resources}/embeds_many_spec.rb +0 -0
  45. data/spec/restly/{associations/embeddable_resources → embeddable_resources}/embeds_one_spec.rb +0 -0
  46. data/spec/restly/{associations/embeddable_resources_spec.rb → embeddable_resources_spec.rb} +0 -0
  47. metadata +23 -11
  48. data/lib/restly/associations/embeddable_resources/embeds_many.rb +0 -11
  49. data/lib/restly/associations/embeddable_resources/embeds_one.rb +0 -11
@@ -14,7 +14,7 @@ module Restly::Base::Instance
14
14
 
15
15
  included do
16
16
  attr_reader :init_options, :response
17
- delegate :spec, to: :klass
17
+ delegate :spec, to: :resource
18
18
  end
19
19
 
20
20
  def initialize(attributes = nil, options = {})
@@ -22,25 +22,19 @@ module Restly::Base::Instance
22
22
  @init_options = options
23
23
  @attributes = HashWithIndifferentAccess.new
24
24
  @association_cache = {}
25
+ @association_attributes = {}
25
26
  @aggregation_cache = {}
26
27
  @attributes_cache = {}
27
28
  @previously_changed = {}
28
29
  @changed_attributes = {}
29
30
 
30
31
  run_callbacks :initialize do
31
-
32
32
  @readonly = options[:readonly] || false
33
33
  set_response options[:response] if options[:response]
34
34
  @loaded = options.has_key?(:loaded) ? options[:loaded] : true
35
35
  self.attributes = attributes if attributes
36
36
  self.connection = options[:connection] if options[:connection].is_a?(OAuth2::AccessToken)
37
- self.path = if response && response.response.env[:url]
38
- response.response.env[:url].path.gsub(/\.\w+$/,'')
39
- elsif respond_to?(:id) && id
40
- [path, id].join('/')
41
- else
42
- klass.path
43
- end
37
+
44
38
  end
45
39
 
46
40
  end
@@ -49,6 +43,31 @@ module Restly::Base::Instance
49
43
  @loaded
50
44
  end
51
45
 
46
+ def connection
47
+ @connection || resource.connection
48
+ end
49
+
50
+ def connection=(val)
51
+ @connection = val
52
+ end
53
+
54
+ def path=(val)
55
+ @path = val
56
+ end
57
+
58
+ def path
59
+ return @path if @path
60
+ if response && response.response.env[:url]
61
+ response.response.env[:url].path.gsub(/\.\w+$/,'')
62
+ elsif respond_to?(:id) && id
63
+ [self.class.path, id].join('/')
64
+ else
65
+ self.class.path
66
+ end
67
+ end
68
+
69
+ private
70
+
52
71
  def set_response(response)
53
72
  raise Restly::Error::InvalidResponse unless response.is_a? OAuth2::Response
54
73
  @response = response
@@ -67,16 +86,4 @@ module Restly::Base::Instance
67
86
  end
68
87
  end
69
88
 
70
- def connection
71
- @connection || self.class.connection
72
- end
73
-
74
- def connection=(val)
75
- @connection = val
76
- end
77
-
78
- def klass
79
- self.class
80
- end
81
-
82
89
  end
@@ -0,0 +1,15 @@
1
+ module Restly::Base::Resource::BatchActions
2
+
3
+ def destroy_all
4
+ !all.map(&:destroy).include?(false)
5
+ end
6
+
7
+ def delete_all
8
+ !all.map(&:delete).include?(false)
9
+ end
10
+
11
+ def update_all(attributes={})
12
+ all.map{ |item| item.update_attributes(attributes) }
13
+ end
14
+
15
+ end
@@ -18,7 +18,7 @@ module Restly::Base::Resource::Finders
18
18
 
19
19
  def collection_from_response(response)
20
20
  raise Restly::Error::InvalidResponse unless response.is_a? OAuth2::Response
21
- Restly::Collection.new self, nil, response: response
21
+ Restly::Collection.new resource, nil, response: response
22
22
  end
23
23
 
24
24
  def instance_from_response(response)
@@ -1,9 +1,14 @@
1
1
  module Restly::Base::Resource
2
2
  extend ActiveSupport::Autoload
3
+
3
4
  autoload :Finders
5
+ autoload :BatchActions
4
6
 
5
7
  include Restly::Base::GenericMethods
6
8
  include Finders
9
+ include BatchActions
10
+
11
+ delegate :first, :last, to: :all
7
12
 
8
13
  # OPTIONS FOR /:path
9
14
  # Fetches the spec of a remote resource
@@ -16,4 +21,8 @@ module Restly::Base::Resource
16
21
  end
17
22
  end
18
23
 
24
+ def resource
25
+ self
26
+ end
27
+
19
28
  end
data/lib/restly/base.rb CHANGED
@@ -8,6 +8,7 @@ module Restly
8
8
  autoload :Includes
9
9
  autoload :MassAssignmentSecurity
10
10
  autoload :Fields
11
+ autoload :EmbeddedAssociations
11
12
 
12
13
  # Thread Local Accessor
13
14
  extend Restly::ThreadLocal
@@ -27,7 +28,7 @@ module Restly
27
28
  include ActiveModel::Serializers::Xml
28
29
 
29
30
  # Set Up Callbacks
30
- define_model_callbacks :create, :save, :delete, :update, :initialize
31
+ define_model_callbacks :create, :save, :destroy, :update, :initialize
31
32
 
32
33
  # Concerned Inheritance
33
34
  include Restly::ConcernedInheritance
@@ -41,11 +42,12 @@ module Restly
41
42
 
42
43
  # Relationships
43
44
  include Restly::Associations
45
+ include Restly::EmbeddedAssociations
44
46
 
45
47
  # Set up the Attributes
46
48
  thread_local_accessor :current_token
49
+ class_attribute :path, instance_writer: false, instance_reader: false
47
50
  class_attribute :resource_name,
48
- :path,
49
51
  :include_root_in_json,
50
52
  :params,
51
53
  :cache,
@@ -70,10 +72,12 @@ module Restly
70
72
  # Run Active Support Load Hooks
71
73
  ActiveSupport.run_load_hooks(:restly, self)
72
74
 
73
- delegate :client, to: :klass
74
-
75
75
  # Alias the class for delegation
76
- def klass
76
+ def client
77
+ self.class.client
78
+ end
79
+
80
+ def resource
77
81
  self.class
78
82
  end
79
83
 
@@ -1,40 +1,69 @@
1
1
  class Restly::Collection < Array
2
- extend ActiveSupport::Autoload
2
+ # extend ActiveSupport::Autoload
3
+ include Restly::Base::Resource::Finders
4
+ include Restly::Base::Resource::BatchActions
5
+ include Restly::Base::GenericMethods
3
6
 
4
- delegate :resource_name, :connection, to: :resource
7
+ delegate :resource_name, :new, :client, to: :resource
5
8
 
6
- autoload :Pagination
9
+ # autoload :Pagination
7
10
 
8
11
  attr_reader :resource
9
12
 
10
- def initialize(resource, array, opts={})
13
+ def initialize(resource, array=[], opts={})
11
14
  @resource = resource
12
15
  @response = opts[:response]
16
+ @connection
13
17
  array = items_from_response if @response.is_a?(OAuth2::Response)
14
18
  super(array)
15
19
  end
16
20
 
17
- def paginate(opts={})
18
- @pagination_opts = opts
19
- collection = self.dup
20
- collection.extend(Restly::Collection::Pagination)
21
- return page(opts[:page]) unless opts[:page] == current_page && opts[:per_page] == response_per_page
22
- collection
21
+ [:path, :connection, :params].each do |attr|
22
+ define_method attr do
23
+ instance_variable_get(:"@#{attr}") || resource.send(attr)
24
+ end
25
+
26
+ define_method "#{attr}=" do |val|
27
+ instance_variable_set(:"@#{attr}", val)
28
+ end
29
+ end
30
+
31
+ def create(*args)
32
+ self << instance = super
33
+ instance
23
34
  end
24
35
 
36
+ def map(*args)
37
+ initialize resource, super
38
+ end
39
+
40
+ alias :collect :map
41
+
42
+ #def paginate(opts={})
43
+ # @pagination_opts = opts
44
+ # collection = self.dup
45
+ # collection.extend(Restly::Collection::Pagination)
46
+ # return page(opts[:page]) unless opts[:page] == current_page && opts[:per_page] == response_per_page
47
+ # collection
48
+ #end
49
+
25
50
  def <<(instance)
26
- raise Restly::Error::InvalidObject, "Object is not an instance of #{resource}" unless instance.is_a?(resource)
51
+ raise Restly::Error::InvalidObject, "Object is not an instance of #{resource}" unless accepts?(instance)
27
52
  super(instance)
28
53
  end
29
54
 
55
+ def reload!
56
+ replace collection_from_response(connection.get path)
57
+ end
58
+
59
+ private
60
+
30
61
  def serializable_hash(options = nil)
31
62
  self.collect do |i|
32
63
  i.serializable_hash(options)
33
64
  end
34
65
  end
35
66
 
36
- private
37
-
38
67
  def items_from_response
39
68
  parsed = @response.parsed || {}
40
69
  parsed = parsed[resource_name.pluralize] if parsed.is_a?(Hash) && parsed[resource_name.pluralize]
@@ -44,4 +73,8 @@ class Restly::Collection < Array
44
73
  end
45
74
  end
46
75
 
76
+ def accepts?(instance)
77
+ instance.class.name == resource.name
78
+ end
79
+
47
80
  end
@@ -1,5 +1,11 @@
1
1
  module Restly::Configuration
2
2
 
3
+ def self.load_config(hash)
4
+ @config = hash.symbolize_keys
5
+ end
6
+
7
+ private
8
+
3
9
  def self.config
4
10
  defaults = {
5
11
  session_key: :access_token,
@@ -27,10 +33,6 @@ module Restly::Configuration
27
33
  config[:client_options].merge(config[:oauth_options])
28
34
  end
29
35
 
30
- def self.load_config(hash)
31
- @config = hash.symbolize_keys
32
- end
33
-
34
36
  def self.method_missing(m, *args, &block)
35
37
  config.with_indifferent_access[m]
36
38
  end
@@ -1,16 +1,11 @@
1
1
  module Restly::ControllerMethods
2
- extend ActiveSupport::Concern
3
2
 
4
- included do
5
-
6
- def auth_token
7
- @oauth_token ||= session[Restly::Configuration.session_key].try(:dup) || {}
8
- end
9
-
10
- def auth_token=(token_object)
11
- session[Restly::Configuration.session_key] = Restly::Connection.tokenize(Restly::Base.client, token_object).to_hash
12
- end
3
+ def auth_token
4
+ @oauth_token ||= session[Restly::Configuration.session_key].try(:dup) || {}
5
+ end
13
6
 
7
+ def auth_token=(token_object)
8
+ session[Restly::Configuration.session_key] = Restly::Connection.tokenize(Restly::Base.client, token_object).to_hash
14
9
  end
15
10
 
16
11
  end
@@ -0,0 +1,7 @@
1
+ class Restly::EmbeddedAssociations::Base < Restly::Associations::Base
2
+
3
+ def embedded?
4
+ true
5
+ end
6
+
7
+ end
@@ -1,9 +1,6 @@
1
- module Restly::Associations::EmbeddableResources
2
- extend ActiveSupport::Autoload
1
+ module Restly::EmbeddedAssociations::ClassMethods
3
2
 
4
- autoload :EmbeddedIn
5
- autoload :EmbedsMany
6
- autoload :EmbedsOne
3
+ private
7
4
 
8
5
  # Embeds One
9
6
  def embeds_resource(name, options = {})
@@ -36,4 +33,16 @@ module Restly::Associations::EmbeddableResources
36
33
 
37
34
  end
38
35
 
36
+ def embedded_in(name, options={})
37
+ self.resource_associations[name] = association = EmbeddedIn.new(self, name, options)
38
+
39
+ define_method name do |options={}|
40
+ get_association(name, options)
41
+ end
42
+
43
+ define_method "#{name}=" do |value|
44
+ set_association name, value
45
+ end
46
+ end
47
+
39
48
  end
@@ -0,0 +1,7 @@
1
+ class Restly::EmbeddableResources::EmbeddedIn < Restly::EmbeddedAssociations::Base
2
+
3
+ def nested?
4
+ true
5
+ end
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ class Restly::EmbeddableResources::EmbedsMany < Restly::EmbeddedAssociations::Base
2
+
3
+ def collection?
4
+ true
5
+ end
6
+
7
+ end
@@ -0,0 +1,3 @@
1
+ class Restly::EmbeddableResources::EmbedsOne < Restly::EmbeddedAssociations::Base
2
+
3
+ end
@@ -0,0 +1,12 @@
1
+ module Restly::EmbeddedAssociations
2
+ extend ActiveSupport::Autoload
3
+
4
+ autoload :EmbeddedIn
5
+ autoload :EmbedsMany
6
+ autoload :EmbedsOne
7
+ autoload :ClassMethods
8
+ autoload :Base
9
+
10
+ extend ActiveSupport::Concern
11
+
12
+ end
data/lib/restly/error.rb CHANGED
@@ -3,7 +3,7 @@ module Restly::Error
3
3
  class StandardError < ::StandardError
4
4
 
5
5
  def message
6
- super.red
6
+ defined?(IRB) ? super.red : super
7
7
  end
8
8
 
9
9
  end
@@ -12,6 +12,8 @@ module Restly::NestedAttributes
12
12
 
13
13
  end
14
14
 
15
+ private
16
+
15
17
  # One To One Association
16
18
  def assign_nested_attributes_for_one_to_one_resource_association(association_name, attributes, assignment_opts = {})
17
19
  options = self.nested_attributes_options[association_name]
@@ -2,15 +2,16 @@ class Restly::Proxies::Associations::Collection < Restly::Proxies::Base
2
2
 
3
3
  attr_reader :parent, :joiner
4
4
 
5
- def initialize(receiver, parent, joiner=nil)
6
- super(receiver)
5
+ def initialize(collection, parent, joiner=nil)
6
+ collection.map!{ |instance| Restly::Proxies::Associations::Instance.new(instance, parent, joiner) }
7
+ super(collection)
7
8
  @parent = parent
8
9
  @joiner = joiner
9
10
  end
10
11
 
11
12
  def <<(instance)
12
- collection = receiver << instance
13
- instance.save unless instance.persisted
13
+ collection = super
14
+ instance = create(instance.attributes) unless instance.persisted?
14
15
  if joiner
15
16
  joiner.create("#{parent.resource_name}_id" => parent.id, "#{instance.resource_name}_id" => instance.id)
16
17
  elsif parent
@@ -2,8 +2,8 @@ class Restly::Proxies::Associations::Instance < Restly::Proxies::Base
2
2
 
3
3
  attr_reader :parent, :joiner
4
4
 
5
- def initialize(receiver, parent, joiner=nil)
6
- super(receiver)
5
+ def initialize(instance, parent, joiner=nil)
6
+ super(instance)
7
7
  @parent = parent
8
8
  @joiner = joiner
9
9
  end
@@ -1,10 +1,13 @@
1
1
  class Restly::Proxies::Base < SimpleDelegator
2
2
 
3
+ delegate :is_a?, :kind_of?, to: :__getobj__
4
+
3
5
  # Initialize the Proxy
4
6
  def initialize(receiver)
5
7
 
6
8
  # Dupe the Requester
7
9
  if receiver.class == Class
10
+
8
11
  @receiver = receiver.dup
9
12
 
10
13
  # Some Key Methods Added to the Duplicated Requester
@@ -31,6 +34,8 @@ class Restly::Proxies::Base < SimpleDelegator
31
34
  super(@receiver)
32
35
  end
33
36
 
37
+ alias_method :proxy_class, :class
38
+
34
39
  # Tell the Proxy its Class!
35
40
  def class
36
41
  @receiver.class
@@ -8,6 +8,8 @@ class Restly::Proxies::WithPath < Restly::Proxies::Base
8
8
  adjust_path_from_options! if @options.present?
9
9
  end
10
10
 
11
+ private
12
+
11
13
  def adjust_path_from_options!
12
14
  prepend = if @options[:prepend]
13
15
  @options[:prepend].gsub(/^([^\/])/, "/\\1").gsub(/\/$/, "")
@@ -1,3 +1,3 @@
1
1
  module Restly
2
- VERSION = "0.0.1.alpha.4"
2
+ VERSION = "0.0.1.alpha.6"
3
3
  end
data/lib/restly.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "colorize"
1
+ require "colorize" if defined?(IRB)
2
2
  require "active_support"
3
3
  require "restly/version"
4
4
  require "oauth2"
@@ -13,6 +13,7 @@ module Restly
13
13
  autoload :Collection
14
14
  autoload :ControllerMethods
15
15
  autoload :Associations
16
+ autoload :EmbeddedAssociations
16
17
  autoload :NestedAttributes
17
18
  autoload :Error
18
19
  autoload :Connection
@@ -0,0 +1,45 @@
1
+ class Api::OtherObjectsController < ApplicationController
2
+
3
+ # Api::OtherObject
4
+
5
+ before_filter do
6
+ nested_in_resources = params.select{ |param| /_id$/ =~ param }
7
+ params[:other_object].merge!(nested_in_resources)
8
+ @resource = Api::OtherObject.where(nested_in_resources) if nested_in_resources.present?
9
+ end
10
+
11
+ def index
12
+ render json: @other_objects = @resource.all
13
+ end
14
+
15
+ def create
16
+ render json: if (@other_object = Api::OtherObject.create(params[:other_object]))
17
+ @other_object
18
+ else
19
+ flash.now "Something bad Happened"
20
+ end
21
+ end
22
+
23
+ def show
24
+ render json: @other_object = Api::OtherObject.find(params[:id])
25
+ end
26
+
27
+ def update
28
+ @other_object = Api::OtherObject.find(params[:id])
29
+ render json: if @other_object.update_attributes(params[:other_object])
30
+ @other_object
31
+ else
32
+ "Something bad Happened"
33
+ end
34
+ end
35
+
36
+ def destroy
37
+ @other_object = Api::OtherObject.find(params[:id])
38
+ render json: if @other_object.delete
39
+ { success: true }
40
+ else
41
+ "Something bad Happened"
42
+ end
43
+ end
44
+
45
+ end
@@ -5,8 +5,8 @@ class Api::SampleObjectsController < ApplicationController
5
5
  end
6
6
 
7
7
  def create
8
- if (@sample_object = Api::SampleObject.create(params[:sample_object]))
9
- redirect_to @sample_object
8
+ render json: if (@sample_object = Api::SampleObject.create(params[:sample_object]))
9
+ @sample_object
10
10
  else
11
11
  flash.now "Something bad Happened"
12
12
  end
@@ -19,7 +19,7 @@ class Api::SampleObjectsController < ApplicationController
19
19
  def update
20
20
  @sample_object = Api::SampleObject.find(params[:id])
21
21
  render json: if @sample_object.update_attributes(params[:sample_object])
22
- redirect_to @sample_object
22
+ @sample_object
23
23
  else
24
24
  "Something bad Happened"
25
25
  end
@@ -28,7 +28,7 @@ class Api::SampleObjectsController < ApplicationController
28
28
  def destroy
29
29
  @sample_object = Api::SampleObject.find(params[:id])
30
30
  render json: if @sample_object.delete
31
- redirect_to sample_objects_path
31
+ { success: true }
32
32
  else
33
33
  "Something bad Happened"
34
34
  end
@@ -6,7 +6,10 @@ class OtherObject < Restly::Base
6
6
 
7
7
  field :foo_var
8
8
  field :bar_lee
9
+ field :sample_object_id
9
10
  field :created_at
10
11
  field :updated_at
11
12
 
13
+ attr_protected :created_at, :updated_at, :id
14
+
12
15
  end
@@ -12,4 +12,6 @@ class SampleObject < Restly::Base
12
12
  field :created_at
13
13
  field :updated_at
14
14
 
15
+ attr_protected :created_at, :updated_at, :id
16
+
15
17
  end
@@ -1,7 +1,10 @@
1
1
  Dummy::Application.routes.draw do
2
2
  root to: "sample_objects#index"
3
3
  resources :sample_objects
4
+
4
5
  namespace :api, format: :json do
5
- resources :sample_objects
6
+ resources :sample_objects do
7
+ resources :other_objects
8
+ end
6
9
  end
7
10
  end