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

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.
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