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
    
        data/.rspec
    ADDED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # Restly
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            Restly is an ActiveModel based ODM (Object Document Mapper) for restful web-services. It includes the ability to define relationships to any Ruby class using some built in helpers.
         | 
| 4 4 |  | 
| 5 5 | 
             
            ## Installation
         | 
| 6 6 |  | 
| @@ -16,9 +16,69 @@ Or install it yourself as: | |
| 16 16 |  | 
| 17 17 | 
             
                $ gem install restly
         | 
| 18 18 |  | 
| 19 | 
            -
            ##  | 
| 19 | 
            +
            ## Configuration
         | 
| 20 | 
            +
            In order for restly to funciton it will need some configuration. This can be done by placing restly.yml in your config directory. We have added a generator to make this easier.
         | 
| 20 21 |  | 
| 21 | 
            -
             | 
| 22 | 
            +
            ```sh
         | 
| 23 | 
            +
            $ rails generate restly:configuration
         | 
| 24 | 
            +
            ```
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            This will generate a file like so:
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            ```yaml
         | 
| 29 | 
            +
            development: &development
         | 
| 30 | 
            +
              site: http://example.com # Change This
         | 
| 31 | 
            +
              default_format: json # defaults to: json
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              ## Would you like requests to be cached?
         | 
| 34 | 
            +
              # cache: true
         | 
| 35 | 
            +
              # cache_options:
         | 
| 36 | 
            +
              #   expires_in: 3600
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              ## Enable Oauth?
         | 
| 39 | 
            +
              # use_oauth: true
         | 
| 40 | 
            +
              # oauth_options:
         | 
| 41 | 
            +
              #   client_id: %client_id%
         | 
| 42 | 
            +
              #   client_secret: %client_secret%
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            test:
         | 
| 45 | 
            +
              <<: *development
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            production:
         | 
| 48 | 
            +
              site: http://example.com # Change This
         | 
| 49 | 
            +
              default_format: json # defaults to: json
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              # Would you like requests to be cached?
         | 
| 52 | 
            +
              cache: true
         | 
| 53 | 
            +
              cache_options:
         | 
| 54 | 
            +
                 expires_in: 3600
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              ## Enable Oauth?
         | 
| 57 | 
            +
              # use_oauth: true
         | 
| 58 | 
            +
              # oauth_options:
         | 
| 59 | 
            +
              #   client_id: %client_id%
         | 
| 60 | 
            +
              #   client_secret: %client_secret%
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            ```
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            ## Creating a Restly Model
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            # Using the generator
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            ```
         | 
| 69 | 
            +
            $ rails generate restly:model MyModel
         | 
| 70 | 
            +
            ```
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            This will generate a model that looks like this:
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            ```ruby
         | 
| 75 | 
            +
            class MyModel < Restly::Base
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              # self.resource_name = 'my_model'
         | 
| 78 | 
            +
              # self.path = 'some_path/to_resource' # defaults to: 'resource_name.pluralized'
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            end
         | 
| 81 | 
            +
            ```
         | 
| 22 82 |  | 
| 23 83 | 
             
            ## Contributing
         | 
| 24 84 |  | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            module Restly
         | 
| 2 | 
            +
              module Generators
         | 
| 3 | 
            +
                class ModelGenerator < Rails::Generators::NamedBase
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  source_root File.expand_path("../templates", __FILE__)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def initialize(args, *options) #:nodoc:
         | 
| 8 | 
            +
                    args[0] = args[0].gsub(/\./,'_')
         | 
| 9 | 
            +
                    super
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def create_model_file
         | 
| 13 | 
            +
                    template "model.rb.erb", "app/models/#{file_name}.rb"
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            development: &development
         | 
| 2 | 
            +
              site: http://example.com # Change This
         | 
| 3 | 
            +
              default_format: json # defaults to: json
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              ## Would you like requests to be cached?
         | 
| 6 | 
            +
              # cache: true
         | 
| 7 | 
            +
              # cache_options:
         | 
| 8 | 
            +
              #   expires_in: 3600
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              ## Enable Oauth?
         | 
| 11 | 
            +
              # use_oauth: true
         | 
| 12 | 
            +
              # oauth_options:
         | 
| 13 | 
            +
              #   client_id: %client_id%
         | 
| 14 | 
            +
              #   client_secret: %client_secret%
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            test:
         | 
| 17 | 
            +
              <<: *development
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            production:
         | 
| 20 | 
            +
              site: http://example.com # Change This
         | 
| 21 | 
            +
              default_format: json # defaults to: json
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              # Would you like requests to be cached?
         | 
| 24 | 
            +
              cache: true
         | 
| 25 | 
            +
              cache_options:
         | 
| 26 | 
            +
                 expires_in: 3600
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              ## Enable Oauth?
         | 
| 29 | 
            +
              # use_oauth: true
         | 
| 30 | 
            +
              # oauth_options:
         | 
| 31 | 
            +
              #   client_id: %client_id%
         | 
| 32 | 
            +
              #   client_secret: %client_secret%
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            class <%= class_name %> < Restly::Base
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              ## Override the Site
         | 
| 4 | 
            +
              # self.site = "anotherexample.com" # defaults to config's site
         | 
| 5 | 
            +
              # self.resource_name = "some_other_name" # defaults to class_name.underscore
         | 
| 6 | 
            +
              # self.path = "/some_other_path" # defaults to: resource_name.pluralized
         | 
| 7 | 
            +
              # self.format = :json # defaults to :json
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            end
         | 
| @@ -12,24 +12,95 @@ class Restly::Associations::Base | |
| 12 12 | 
             
                @options = options
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 | 
            -
              def  | 
| 16 | 
            -
             | 
| 15 | 
            +
              def load(parent, options)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                # Merge Options
         | 
| 18 | 
            +
                options.reverse_merge!(self.options)
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                # Authorize and Set Path
         | 
| 21 | 
            +
                association = authorize(options[:authorize]).with_path(parent, options[:path])
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                # Load Collection or Instance
         | 
| 24 | 
            +
                collection? ? association.load_collection(parent) : association.load_instance(parent)
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def load_collection(parent, association_class = self.association_class)
         | 
| 28 | 
            +
                raise Restly::Error::AssociationError, "Not a collection" unless collection?
         | 
| 29 | 
            +
                Restly::Proxies::Associations::Collection.new(association_class.all, parent)
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def load_instance(parent, association_class = self.association_class)
         | 
| 33 | 
            +
                raise Restly::Error::AssociationError, "Not an instance" if collection?
         | 
| 34 | 
            +
                instance = if (foreign_key = parent.attributes["#{name}_id"])
         | 
| 35 | 
            +
                             association_class.find(foreign_key)
         | 
| 36 | 
            +
                           else
         | 
| 37 | 
            +
                             association_class.instance_from_response association_class.connection.get(association_class.path)
         | 
| 38 | 
            +
                           end
         | 
| 39 | 
            +
                Restly::Proxies::Associations::Instance.new(instance, parent)
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              def valid?(val)
         | 
| 43 | 
            +
                valid_instances = Array.wrap(val).reject{ |item| item.resource_name == @association_class.resource_name }.empty?
         | 
| 44 | 
            +
                raise Restly::Error::InvalidObject, "#{val} is not a #{association_class}" unless valid_instances
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # Stubs
         | 
| 48 | 
            +
              def stub(parent, attributes)
         | 
| 49 | 
            +
                return nil if !parent.is_a?(Restly::Base) || !attributes.present?
         | 
| 50 | 
            +
                collection? ? stub_collection(parent, attributes) : stub_instance(parent, attributes)
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def stub_collection(parent, attributes)
         | 
| 54 | 
            +
                collection = attributes.map{ |item_attrs| association_class.new(item_attrs, loaded: embedded?) }
         | 
| 55 | 
            +
                Restly::Proxies::Associations::Collection.new(collection, parent)
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              def stub_instance(parent, attributes)
         | 
| 59 | 
            +
                instance = association_class.new(attributes, loaded: embedded?)
         | 
| 60 | 
            +
                Restly::Proxies::Associations::Instance.new(instance, parent)
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              # Build
         | 
| 64 | 
            +
              def build(parent, attributes = nil, options = {})
         | 
| 65 | 
            +
                raise NoMethodError, "Build not available for collection." if collection?
         | 
| 66 | 
            +
                instance = association_class.new(attributes, options)
         | 
| 67 | 
            +
                instance.write_attribute("#{@owner.resource_name}_id", parent.id) if association_class.method_defined?("#{@owner.resource_name}_id")
         | 
| 68 | 
            +
                Restly::Proxies::Associations::Instance.new(instance, parent)
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              # Modifiers
         | 
| 72 | 
            +
              def authorize(authorization = nil, association_class=self.association_class)
         | 
| 73 | 
            +
                duplicate = self.dup
         | 
| 74 | 
            +
                duplicate.instance_variable_set :@association_class, if (!association_class.authorized? && @owner.respond_to?(:authorized?) && @owner.authorized?) || authorization
         | 
| 75 | 
            +
                                                                       association_class.authorize(authorization || @owner.connection)
         | 
| 76 | 
            +
                                                                     else
         | 
| 77 | 
            +
                                                                       association_class
         | 
| 78 | 
            +
                                                                     end
         | 
| 79 | 
            +
                duplicate
         | 
| 17 80 | 
             
              end
         | 
| 18 81 |  | 
| 19 | 
            -
              def  | 
| 20 | 
            -
                 | 
| 21 | 
            -
                 | 
| 22 | 
            -
             | 
| 82 | 
            +
              def with_path(parent, path = nil, association_class=self.association_class)
         | 
| 83 | 
            +
                duplicate = self.dup
         | 
| 84 | 
            +
                duplicate.instance_variable_set :@association_class, if path
         | 
| 85 | 
            +
                                                                       association_class.with_path(path)
         | 
| 86 | 
            +
                                                                     else
         | 
| 87 | 
            +
                                                                       association_class.with_path(association_resource_name, prepend: parent.path)
         | 
| 88 | 
            +
                                                                     end
         | 
| 89 | 
            +
                duplicate
         | 
| 23 90 | 
             
              end
         | 
| 24 91 |  | 
| 25 92 | 
             
              private
         | 
| 26 93 |  | 
| 27 | 
            -
              def  | 
| 28 | 
            -
                 | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
                 | 
| 94 | 
            +
              def collection?
         | 
| 95 | 
            +
                false
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              def embedded?
         | 
| 99 | 
            +
                false
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              def association_resource_name
         | 
| 103 | 
            +
                collection? ? association_class.resource_name.pluralize : association_class.resource_name
         | 
| 33 104 | 
             
              end
         | 
| 34 105 |  | 
| 35 106 | 
             
            end
         | 
| @@ -1,11 +1,28 @@ | |
| 1 1 | 
             
            class Restly::Associations::BelongsTo < Restly::Associations::Base
         | 
| 2 2 |  | 
| 3 | 
            -
              def  | 
| 4 | 
            -
                 | 
| 5 | 
            -
             | 
| 6 | 
            -
                 | 
| 7 | 
            -
             | 
| 8 | 
            -
                 | 
| 3 | 
            +
              def load(parent, options)
         | 
| 4 | 
            +
                if polymorphic
         | 
| 5 | 
            +
                  set_polymorphic_class(parent).load(parent, options)
         | 
| 6 | 
            +
                else
         | 
| 7 | 
            +
                  super(parent, options)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              def set_polymorphic_class(parent)
         | 
| 12 | 
            +
                duplicate = self.dup
         | 
| 13 | 
            +
                duplicate.instance_variable_set(:@association_class, parent.send("#{name}_type"))
         | 
| 14 | 
            +
                duplicate.instance_variable_set(:@polymorphic, false)
         | 
| 15 | 
            +
                duplicate
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def with_path(parent, path = nil, association_class=self.association_class)
         | 
| 19 | 
            +
                duplicate = self.dup
         | 
| 20 | 
            +
                duplicate.instance_variable_set :@association_class, if path
         | 
| 21 | 
            +
                                                                       association_class.with_path(path)
         | 
| 22 | 
            +
                                                                     else
         | 
| 23 | 
            +
                                                                       association_class
         | 
| 24 | 
            +
                                                                     end
         | 
| 25 | 
            +
                duplicate
         | 
| 9 26 | 
             
              end
         | 
| 10 27 |  | 
| 11 28 | 
             
              def collection?
         | 
| @@ -10,9 +10,15 @@ module Restly::Associations::EmbeddableResources | |
| 10 10 | 
             
                exclude_field(name) if ancestors.include?(Restly::Base)
         | 
| 11 11 | 
             
                self.resource_associations[name] = association = EmbedsOne.new(self, name, options)
         | 
| 12 12 |  | 
| 13 | 
            -
                define_method name do
         | 
| 14 | 
            -
                   | 
| 13 | 
            +
                define_method name do |options={}|
         | 
| 14 | 
            +
                  return get_association(name) if get_association(name).present?
         | 
| 15 | 
            +
                  set_association name, association.stub(self)
         | 
| 15 16 | 
             
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                define_method "#{name}=" do |value|
         | 
| 19 | 
            +
                  set_association name, value
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 16 22 | 
             
              end
         | 
| 17 23 |  | 
| 18 24 | 
             
              # Embeds Many
         | 
| @@ -20,9 +26,14 @@ module Restly::Associations::EmbeddableResources | |
| 20 26 | 
             
                exclude_field(name) if ancestors.include?(Restly::Base)
         | 
| 21 27 | 
             
                self.resource_associations[name] = association = EmbedsMany.new(self, name, options)
         | 
| 22 28 |  | 
| 23 | 
            -
                define_method name do
         | 
| 24 | 
            -
                  ( | 
| 29 | 
            +
                define_method name do |options={}|
         | 
| 30 | 
            +
                  get_association(name, options)
         | 
| 25 31 | 
             
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                define_method "#{name}=" do |value|
         | 
| 34 | 
            +
                  set_association name, value
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 26 37 | 
             
              end
         | 
| 27 38 |  | 
| 28 39 | 
             
            end
         | 
| @@ -7,15 +7,6 @@ class Restly::Associations::HasMany < Restly::Associations::Base | |
| 7 7 | 
             
                super
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 | 
            -
              def scope_with_parent(parent, options)
         | 
| 11 | 
            -
                options.reverse_merge!(self.options)
         | 
| 12 | 
            -
                association_class = polymorphic ? [@namespace, instance.send("#{name}_type")] : self.association_class
         | 
| 13 | 
            -
                association_class = authorize(association_class, options[:authorize])
         | 
| 14 | 
            -
                collection = association_class.with_params("with_#{parent.resource_name}_id" => parent.id).all # (parent.attributes["#{name}_id"])
         | 
| 15 | 
            -
                collection.select{|i| i.attributes["#{parent.resource_name}_id"] == parent.id }
         | 
| 16 | 
            -
                Restly::Proxies::Associations::Collection.new(collection, parent)
         | 
| 17 | 
            -
              end
         | 
| 18 | 
            -
             | 
| 19 10 | 
             
              def collection?
         | 
| 20 11 | 
             
                true
         | 
| 21 12 | 
             
              end
         | 
| @@ -7,15 +7,6 @@ class Restly::Associations::HasOne < Restly::Associations::Base | |
| 7 7 | 
             
                super
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 | 
            -
              def scope_with_parent(parent, options)
         | 
| 11 | 
            -
                options.reverse_merge!(self.options)
         | 
| 12 | 
            -
                association_class = polymorphic ? [@namespace, instance.send("#{name}_type")] : self.association_class
         | 
| 13 | 
            -
                association_class = authorize(association_class, options[:authorize])
         | 
| 14 | 
            -
                collection = association_class.with_params("with_#{parent.resource_name}_id" => parent.id).all(parent.attributes["#{name}_id"])
         | 
| 15 | 
            -
                collection.select{|i| i.attributes["#{parent.resource_name}_id"] == parent.id }.first
         | 
| 16 | 
            -
                Restly::Proxies::Associations::Instance.new(instance, parent)
         | 
| 17 | 
            -
              end
         | 
| 18 | 
            -
             | 
| 19 10 | 
             
              def collection?
         | 
| 20 11 | 
             
                true
         | 
| 21 12 | 
             
              end
         | 
    
        data/lib/restly/associations.rb
    CHANGED
    
    | @@ -10,17 +10,30 @@ module Restly::Associations | |
| 10 10 | 
             
              autoload :HasOneThrough
         | 
| 11 11 | 
             
              autoload :EmbeddableResources
         | 
| 12 12 |  | 
| 13 | 
            -
              class  | 
| 13 | 
            +
              class AssociationsSet < HashWithIndifferentAccess
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              class IndifferentSet < Set
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def include?(attr)
         | 
| 19 | 
            +
                  return super unless attr.is_a?(Symbol) || attr.is_a?(String)
         | 
| 20 | 
            +
                  super(attr.to_s) || super(attr.to_sym)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 14 23 | 
             
              end
         | 
| 15 24 |  | 
| 16 25 | 
             
              included do
         | 
| 17 26 |  | 
| 18 | 
            -
                 | 
| 27 | 
            +
                include Restly::ConcernedInheritance
         | 
| 28 | 
            +
                extend  EmbeddableResources if self == Restly::Base
         | 
| 19 29 | 
             
                include Restly::NestedAttributes
         | 
| 20 30 |  | 
| 21 31 | 
             
                delegate :resource_name, to: :klass
         | 
| 22 32 | 
             
                class_attribute :resource_associations, instance_reader: false, instance_writer: false
         | 
| 23 | 
            -
             | 
| 33 | 
            +
             | 
| 34 | 
            +
                attr_reader :association_attributes
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                self.resource_associations = AssociationsSet.new
         | 
| 24 37 |  | 
| 25 38 | 
             
                inherited do
         | 
| 26 39 | 
             
                  self.resource_associations = resource_associations.dup
         | 
| @@ -28,12 +41,42 @@ module Restly::Associations | |
| 28 41 |  | 
| 29 42 | 
             
              end
         | 
| 30 43 |  | 
| 31 | 
            -
              def  | 
| 32 | 
            -
                 | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 44 | 
            +
              def associations
         | 
| 45 | 
            +
                IndifferentSet.new klass.reflect_on_all_resource_associations.keys.map(&:to_sym)
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def set_association(attr, val)
         | 
| 49 | 
            +
                association = klass.reflect_on_resource_association(attr)
         | 
| 50 | 
            +
                association.valid?(val)
         | 
| 51 | 
            +
                @association_attributes[attr] = val
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def get_association(attr, options={})
         | 
| 55 | 
            +
                association = klass.reflect_on_resource_association(attr)
         | 
| 56 | 
            +
                (@association_attributes ||= {}.with_indifferent_access)[attr] || set_association(attr, association.load(self, options))
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def respond_to_association?(m)
         | 
| 60 | 
            +
                !!(/(?<attr>\w+)(?<setter>=)?$/ =~ m.to_s) && associations.include?(attr.to_sym)
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def respond_to?(m, include_private = false)
         | 
| 64 | 
            +
                respond_to_association?(m) || super
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              private
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              def method_missing(m, *args, &block)
         | 
| 70 | 
            +
                if !!(/(?<attr>\w+)(?<setter>=)?$/ =~ m.to_s) && associations.include?(m)
         | 
| 71 | 
            +
                  attr = attr.to_sym
         | 
| 72 | 
            +
                  case !!setter
         | 
| 73 | 
            +
                    when true
         | 
| 74 | 
            +
                      set_association(attr, *args)
         | 
| 75 | 
            +
                    when false
         | 
| 76 | 
            +
                      get_association(attr)
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                else
         | 
| 79 | 
            +
                  super(m, *args, &block)
         | 
| 37 80 | 
             
                end
         | 
| 38 81 | 
             
              end
         | 
| 39 82 |  | 
| @@ -47,6 +90,10 @@ module Restly::Associations | |
| 47 90 | 
             
                  name.gsub(/.*::/,'').underscore
         | 
| 48 91 | 
             
                end
         | 
| 49 92 |  | 
| 93 | 
            +
                def reflect_on_resource_association(association_name)
         | 
| 94 | 
            +
                  reflect_on_all_resource_associations[association_name]
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 50 97 | 
             
                def reflect_on_all_resource_associations
         | 
| 51 98 | 
             
                  resource_associations
         | 
| 52 99 | 
             
                end
         | 
| @@ -57,32 +104,45 @@ module Restly::Associations | |
| 57 104 | 
             
                def belongs_to_resource(name, options = {})
         | 
| 58 105 | 
             
                  exclude_field(name) if ancestors.include?(Restly::Base)
         | 
| 59 106 | 
             
                  self.resource_associations[name] = association = BelongsTo.new(self, name, options)
         | 
| 107 | 
            +
             | 
| 60 108 | 
             
                  define_method name do |options={}|
         | 
| 61 | 
            -
                     | 
| 109 | 
            +
                    get_association(name, options)
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  define_method "#{name}=" do |value|
         | 
| 113 | 
            +
                    set_association name, value
         | 
| 62 114 | 
             
                  end
         | 
| 115 | 
            +
             | 
| 63 116 | 
             
                end
         | 
| 64 117 |  | 
| 65 118 | 
             
                # Has One
         | 
| 66 119 | 
             
                def has_one_resource(name, options = {})
         | 
| 67 120 | 
             
                  exclude_field(name) if ancestors.include?(Restly::Base)
         | 
| 68 121 | 
             
                  self.resource_associations[name] = association = HasOne.new(self, name, options)
         | 
| 122 | 
            +
             | 
| 69 123 | 
             
                  define_method name do |options={}|
         | 
| 70 | 
            -
                     | 
| 124 | 
            +
                    get_association(name, options)
         | 
| 125 | 
            +
                  end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                  define_method "#{name}=" do |value|
         | 
| 128 | 
            +
                    set_association name, value
         | 
| 71 129 | 
             
                  end
         | 
| 130 | 
            +
             | 
| 72 131 | 
             
                end
         | 
| 73 132 |  | 
| 74 133 | 
             
                # Has One
         | 
| 75 134 | 
             
                def has_many_resources(name, options = {})
         | 
| 76 135 | 
             
                  exclude_field(name) if ancestors.include?(Restly::Base)
         | 
| 77 136 | 
             
                  self.resource_associations[name] = association = HasMany.new(self, name, options)
         | 
| 137 | 
            +
             | 
| 78 138 | 
             
                  define_method name do |options={}|
         | 
| 79 | 
            -
                     | 
| 139 | 
            +
                    get_association(name, options)
         | 
| 80 140 | 
             
                  end
         | 
| 81 | 
            -
                end
         | 
| 82 141 |  | 
| 142 | 
            +
                  define_method "#{name}=" do |value|
         | 
| 143 | 
            +
                    set_association name, value
         | 
| 144 | 
            +
                  end
         | 
| 83 145 |  | 
| 84 | 
            -
                def reflect_on_resource_association(association_name)
         | 
| 85 | 
            -
                  reflect_on_all_resource_associations[association_name]
         | 
| 86 146 | 
             
                end
         | 
| 87 147 |  | 
| 88 148 | 
             
              end
         | 
| @@ -1,11 +1,15 @@ | |
| 1 1 | 
             
            module Restly::Base::GenericMethods
         | 
| 2 2 |  | 
| 3 3 | 
             
              def authorize(token_object)
         | 
| 4 | 
            -
                Restly::Proxies:: | 
| 4 | 
            +
                Restly::Proxies::Authorization.new self, token_object
         | 
| 5 5 | 
             
              end
         | 
| 6 6 |  | 
| 7 7 | 
             
              def with_params(params={})
         | 
| 8 | 
            -
                Restly::Proxies:: | 
| 8 | 
            +
                Restly::Proxies::WithParams.new self, params
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              def with_path(*args)
         | 
| 12 | 
            +
                Restly::Proxies::WithPath.new self, *args
         | 
| 9 13 | 
             
              end
         | 
| 10 14 |  | 
| 11 15 | 
             
              def path_with_format(*args)
         | 
| @@ -21,4 +25,8 @@ module Restly::Base::GenericMethods | |
| 21 25 | 
             
                connection.token.present?
         | 
| 22 26 | 
             
              end
         | 
| 23 27 |  | 
| 28 | 
            +
              def proxied?
         | 
| 29 | 
            +
                true
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 24 32 | 
             
            end
         | 
    
        data/lib/restly/base/includes.rb
    CHANGED
    
    | @@ -1,18 +1,6 @@ | |
| 1 1 | 
             
            module Restly::Base::Includes
         | 
| 2 2 | 
             
              extend ActiveSupport::Concern
         | 
| 3 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 4 | 
             
              module ClassMethods
         | 
| 17 5 |  | 
| 18 6 | 
             
                # Delegate stuff to client
         | 
| @@ -38,16 +26,6 @@ module Restly::Base::Includes | |
| 38 26 | 
             
                  resource_name
         | 
| 39 27 | 
             
                end
         | 
| 40 28 |  | 
| 41 | 
            -
                private
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                def inherited(subclass = nil, &block)
         | 
| 44 | 
            -
                  self.inherited_callbacks << block and return if block_given?
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  inherited_callbacks.each do |call_block|
         | 
| 47 | 
            -
                    subclass.class_eval(&call_block)
         | 
| 48 | 
            -
                  end
         | 
| 49 | 
            -
                end
         | 
| 50 | 
            -
             | 
| 51 29 | 
             
              end
         | 
| 52 30 |  | 
| 53 31 | 
             
            end
         |