motion-resource 0.0.1
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/.gitignore +9 -0
 - data/Gemfile +8 -0
 - data/README.md +53 -0
 - data/Rakefile +14 -0
 - data/app/app_delegate.rb +7 -0
 - data/examples/Colr/.gitignore +13 -0
 - data/examples/Colr/Rakefile +10 -0
 - data/examples/Colr/app/app_delegate.rb +10 -0
 - data/examples/Colr/app/color.rb +15 -0
 - data/examples/Colr/app/color_view_controller.rb +46 -0
 - data/examples/Colr/app/initializer.rb +2 -0
 - data/examples/Colr/app/main_navigation_controller.rb +6 -0
 - data/examples/Colr/app/tag.rb +5 -0
 - data/examples/Colr/app/tags_view_controller.rb +23 -0
 - data/lib/motion-resource.rb +5 -0
 - data/lib/motion-resource/associations.rb +94 -0
 - data/lib/motion-resource/attributes.rb +37 -0
 - data/lib/motion-resource/base.rb +51 -0
 - data/lib/motion-resource/crud.rb +33 -0
 - data/lib/motion-resource/find.rb +67 -0
 - data/lib/motion-resource/requests.rb +64 -0
 - data/lib/motion-resource/string.rb +23 -0
 - data/lib/motion-resource/urls.rb +29 -0
 - data/lib/motion-resource/version.rb +3 -0
 - data/motion-resource.gemspec +20 -0
 - data/spec/env.rb +41 -0
 - data/spec/motion-resource/associations/belongs_to_spec.rb +116 -0
 - data/spec/motion-resource/associations/has_many_spec.rb +128 -0
 - data/spec/motion-resource/associations/has_one_spec.rb +69 -0
 - data/spec/motion-resource/associations/scope_spec.rb +21 -0
 - data/spec/motion-resource/attributes_spec.rb +64 -0
 - data/spec/motion-resource/base_spec.rb +54 -0
 - data/spec/motion-resource/crud_spec.rb +141 -0
 - data/spec/motion-resource/find_spec.rb +90 -0
 - data/spec/motion-resource/requests_spec.rb +119 -0
 - data/spec/motion-resource/string_spec.rb +26 -0
 - data/spec/motion-resource/urls_spec.rb +52 -0
 - metadata +140 -0
 
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # MotionResource
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            This is a library for using JSON APIs in RubyMotion apps. It is based on [RemoteModel](https://github.com/clayallsopp/remote_model), however it is an almost complete rewrite. Also, it is inspired by ActiveResource.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Add MotionResource to your Gemfile, like this:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                gem "motion-resource"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            ## Example
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Consider this example for a fictional blog API.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                class User < RemoteModule::RemoteModel
         
     | 
| 
      
 16 
     | 
    
         
            +
                  attr_accessor :id
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  has_many :posts
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  collection_url "users"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  member_url "users/:id"
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                class Post < RemoteModule::RemoteModel
         
     | 
| 
      
 25 
     | 
    
         
            +
                  attr_accessor :id, :user_id, :title, :text
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  belongs_to :user
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  collection_url "users/:user_id/posts"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  member_url "users/:user_id/posts/:id"
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            Now, we can access a user's posts like that:
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                User.find(1) do |user|
         
     | 
| 
      
 36 
     | 
    
         
            +
                  user.posts do |posts|
         
     | 
| 
      
 37 
     | 
    
         
            +
                    puts posts.inspect
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            Note that the blocks are called asynchronously.
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            ## Setup
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            You can configure every model separately; however you will most likely want to configure things like the root_url the same for every model:
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                MotionResource::Base.root_url = "http://localhost:3000/"
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            Don't forget the trailing '/' here!
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            # Forking
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            Feel free to fork and submit pull requests!
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env rake
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.unshift("/Library/RubyMotion/lib")
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'motion/project'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "bundler/gem_tasks"
         
     | 
| 
      
 5 
     | 
    
         
            +
            Bundler.setup
         
     | 
| 
      
 6 
     | 
    
         
            +
            Bundler.require
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            $:.unshift("./lib/")
         
     | 
| 
      
 9 
     | 
    
         
            +
            require './lib/motion-resource'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            Motion::Project::App.setup do |app|
         
     | 
| 
      
 12 
     | 
    
         
            +
              # Use `rake config' to see complete project settings.
         
     | 
| 
      
 13 
     | 
    
         
            +
              app.name = 'MotionResource'
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
    
        data/app/app_delegate.rb
    ADDED
    
    
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- coding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.unshift("/Library/RubyMotion/lib")
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'motion/project'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'motion-support'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'motion-resource'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Motion::Project::App.setup do |app|
         
     | 
| 
      
 8 
     | 
    
         
            +
              # Use `rake config' to see complete project settings.
         
     | 
| 
      
 9 
     | 
    
         
            +
              app.name = 'Colr'
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class AppDelegate
         
     | 
| 
      
 2 
     | 
    
         
            +
              attr_reader :window
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
              def application(application, didFinishLaunchingWithOptions:launchOptions)
         
     | 
| 
      
 5 
     | 
    
         
            +
                @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
         
     | 
| 
      
 6 
     | 
    
         
            +
                @window.rootViewController = MainNavigationController.alloc.init
         
     | 
| 
      
 7 
     | 
    
         
            +
                @window.makeKeyAndVisible
         
     | 
| 
      
 8 
     | 
    
         
            +
                true
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Color < MotionResource::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              attr_accessor :hex
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
              has_many :tags
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              scope :random, :url => 'json/colors/random/7'
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              def ui_color
         
     | 
| 
      
 9 
     | 
    
         
            +
                pointer = Pointer.new(:uint)
         
     | 
| 
      
 10 
     | 
    
         
            +
                scanner = NSScanner.scannerWithString(self.hex)
         
     | 
| 
      
 11 
     | 
    
         
            +
                scanner.scanHexInt(pointer)
         
     | 
| 
      
 12 
     | 
    
         
            +
                rgbValue = pointer[0]
         
     | 
| 
      
 13 
     | 
    
         
            +
                return UIColor.colorWithRed(((rgbValue & 0xFF0000) >> 16)/255.0, green:((rgbValue & 0xFF00) >> 8)/255.0, blue:(rgbValue & 0xFF)/255.0, alpha:1.0)
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class ColorViewController < UITableViewController
         
     | 
| 
      
 2 
     | 
    
         
            +
              attr_accessor :colors
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
              def init
         
     | 
| 
      
 5 
     | 
    
         
            +
                self.colors = []
         
     | 
| 
      
 6 
     | 
    
         
            +
                self.title = "7 random colors"
         
     | 
| 
      
 7 
     | 
    
         
            +
                super
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              def viewDidLoad
         
     | 
| 
      
 11 
     | 
    
         
            +
                load_data
         
     | 
| 
      
 12 
     | 
    
         
            +
                super
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
              def tableView(tableView, numberOfRowsInSection:section)
         
     | 
| 
      
 16 
     | 
    
         
            +
                self.colors.size
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              def tableView(tableView, cellForRowAtIndexPath:indexPath)
         
     | 
| 
      
 20 
     | 
    
         
            +
                cell = tableView.dequeueReusableCellWithIdentifier('Cell')
         
     | 
| 
      
 21 
     | 
    
         
            +
                cell ||= UITableViewCell.alloc.initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier:'Cell')
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                color = colors[indexPath.row]
         
     | 
| 
      
 24 
     | 
    
         
            +
                cell.textLabel.text = color.hex
         
     | 
| 
      
 25 
     | 
    
         
            +
                cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator
         
     | 
| 
      
 26 
     | 
    
         
            +
                cell
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              def tableView(tableView, willDisplayCell:cell, forRowAtIndexPath:indexPath)
         
     | 
| 
      
 30 
     | 
    
         
            +
                color = colors[indexPath.row]
         
     | 
| 
      
 31 
     | 
    
         
            +
                cell.backgroundColor = color.ui_color
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
              
         
     | 
| 
      
 34 
     | 
    
         
            +
              def tableView(tableView, didSelectRowAtIndexPath:indexPath)
         
     | 
| 
      
 35 
     | 
    
         
            +
                navigationController.pushViewController(TagsViewController.alloc.initWithColor(colors[indexPath.row]), animated:true)
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
              
         
     | 
| 
      
 38 
     | 
    
         
            +
              def load_data
         
     | 
| 
      
 39 
     | 
    
         
            +
                Color.random do |results|
         
     | 
| 
      
 40 
     | 
    
         
            +
                  if results
         
     | 
| 
      
 41 
     | 
    
         
            +
                    self.colors = results
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  tableView.reloadData
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class TagsViewController < UITableViewController
         
     | 
| 
      
 2 
     | 
    
         
            +
              attr_accessor :color
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
              def initWithColor(color)
         
     | 
| 
      
 5 
     | 
    
         
            +
                self.color = color
         
     | 
| 
      
 6 
     | 
    
         
            +
                self.title = "Tags for color #{color.hex}"
         
     | 
| 
      
 7 
     | 
    
         
            +
                init
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              def tableView(tableView, numberOfRowsInSection:section)
         
     | 
| 
      
 11 
     | 
    
         
            +
                self.color.tags.size
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              def tableView(tableView, cellForRowAtIndexPath:indexPath)
         
     | 
| 
      
 15 
     | 
    
         
            +
                cell = tableView.dequeueReusableCellWithIdentifier('Cell')
         
     | 
| 
      
 16 
     | 
    
         
            +
                cell ||= UITableViewCell.alloc.initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier:'Cell')
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                tag = color.tags[indexPath.row]
         
     | 
| 
      
 19 
     | 
    
         
            +
                cell.textLabel.text = tag.name
         
     | 
| 
      
 20 
     | 
    
         
            +
                cell.selectionStyle = UITableViewCellSelectionStyleNone
         
     | 
| 
      
 21 
     | 
    
         
            +
                cell
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,94 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MotionResource
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def has_one(name)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    define_method name do
         
     | 
| 
      
 6 
     | 
    
         
            +
                      instance_variable_get("@#{name}")
         
     | 
| 
      
 7 
     | 
    
         
            +
                    end
         
     | 
| 
      
 8 
     | 
    
         
            +
                    
         
     | 
| 
      
 9 
     | 
    
         
            +
                    define_method "#{name}=" do |value|
         
     | 
| 
      
 10 
     | 
    
         
            +
                      klass = Object.const_get(name.to_s.classify)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      value = klass.instantiate(value) if value.is_a?(Hash)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      instance_variable_set("@#{name}", value)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
                    
         
     | 
| 
      
 15 
     | 
    
         
            +
                    define_method "reset_#{name}" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                      instance_variable_set("@#{name}", nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def has_many(name, params = lambda { |o| Hash.new })
         
     | 
| 
      
 21 
     | 
    
         
            +
                    backwards_association = self.name.underscore
         
     | 
| 
      
 22 
     | 
    
         
            +
                    
         
     | 
| 
      
 23 
     | 
    
         
            +
                    define_method name do |&block|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      if block.nil?
         
     | 
| 
      
 25 
     | 
    
         
            +
                        instance_variable_get("@#{name}") || []
         
     | 
| 
      
 26 
     | 
    
         
            +
                      else
         
     | 
| 
      
 27 
     | 
    
         
            +
                        cached = instance_variable_get("@#{name}")
         
     | 
| 
      
 28 
     | 
    
         
            +
                        block.call(cached) and return if cached
         
     | 
| 
      
 29 
     | 
    
         
            +
                        
         
     | 
| 
      
 30 
     | 
    
         
            +
                        Object.const_get(name.to_s.classify).find_all(params.call(self)) do |results|
         
     | 
| 
      
 31 
     | 
    
         
            +
                          if results && results.first && results.first.respond_to?("#{backwards_association}=")
         
     | 
| 
      
 32 
     | 
    
         
            +
                            results.each do |result|
         
     | 
| 
      
 33 
     | 
    
         
            +
                              result.send("#{backwards_association}=", self)
         
     | 
| 
      
 34 
     | 
    
         
            +
                            end
         
     | 
| 
      
 35 
     | 
    
         
            +
                          end
         
     | 
| 
      
 36 
     | 
    
         
            +
                          instance_variable_set("@#{name}", results)
         
     | 
| 
      
 37 
     | 
    
         
            +
                          block.call(results)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        end
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    
         
     | 
| 
      
 42 
     | 
    
         
            +
                    define_method "#{name}=" do |array|
         
     | 
| 
      
 43 
     | 
    
         
            +
                      klass = Object.const_get(name.to_s.classify)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      instance_variable_set("@#{name}", [])
         
     | 
| 
      
 45 
     | 
    
         
            +
                      
         
     | 
| 
      
 46 
     | 
    
         
            +
                      array.each do |value|
         
     | 
| 
      
 47 
     | 
    
         
            +
                        value = klass.instantiate(value) if value.is_a?(Hash)
         
     | 
| 
      
 48 
     | 
    
         
            +
                        instance_variable_get("@#{name}") << value
         
     | 
| 
      
 49 
     | 
    
         
            +
                      end
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                    
         
     | 
| 
      
 52 
     | 
    
         
            +
                    define_method "reset_#{name}" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                      instance_variable_set("@#{name}", nil)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def belongs_to(name, params = lambda { |o| Hash.new })
         
     | 
| 
      
 58 
     | 
    
         
            +
                    define_method name do |&block|
         
     | 
| 
      
 59 
     | 
    
         
            +
                      if block.nil?
         
     | 
| 
      
 60 
     | 
    
         
            +
                        instance_variable_get("@#{name}")
         
     | 
| 
      
 61 
     | 
    
         
            +
                      else
         
     | 
| 
      
 62 
     | 
    
         
            +
                        cached = instance_variable_get("@#{name}")
         
     | 
| 
      
 63 
     | 
    
         
            +
                        block.call(cached) and return if cached
         
     | 
| 
      
 64 
     | 
    
         
            +
                      
         
     | 
| 
      
 65 
     | 
    
         
            +
                        Object.const_get(name.to_s.classify).find(self.send("#{name}_id"), params.call(self)) do |result|
         
     | 
| 
      
 66 
     | 
    
         
            +
                          instance_variable_set("@#{name}", result)
         
     | 
| 
      
 67 
     | 
    
         
            +
                          block.call(result)
         
     | 
| 
      
 68 
     | 
    
         
            +
                        end
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                    
         
     | 
| 
      
 72 
     | 
    
         
            +
                    define_method "#{name}=" do |value|
         
     | 
| 
      
 73 
     | 
    
         
            +
                      klass = Object.const_get(name.to_s.classify)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      value = klass.instantiate(value) if value.is_a?(Hash)
         
     | 
| 
      
 75 
     | 
    
         
            +
                      instance_variable_set("@#{name}", value)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                    
         
     | 
| 
      
 78 
     | 
    
         
            +
                    define_method "reset_#{name}" do
         
     | 
| 
      
 79 
     | 
    
         
            +
                      instance_variable_set("@#{name}", nil)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def scope(name, options = {})
         
     | 
| 
      
 86 
     | 
    
         
            +
                    custom_urls "#{name}_url" => options[:url] if options[:url]
         
     | 
| 
      
 87 
     | 
    
         
            +
                    
         
     | 
| 
      
 88 
     | 
    
         
            +
                    metaclass.send(:define_method, name) do |&block|
         
     | 
| 
      
 89 
     | 
    
         
            +
                      fetch_collection(send("#{name}_url"), &block)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MotionResource
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                class_inheritable_array :attributes
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def attribute(*fields)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    attr_reader *fields
         
     | 
| 
      
 8 
     | 
    
         
            +
                    fields.each do |field|
         
     | 
| 
      
 9 
     | 
    
         
            +
                      define_method "#{field}=" do |value|
         
     | 
| 
      
 10 
     | 
    
         
            +
                        if value.is_a?(Hash) || value.is_a?(Array)
         
     | 
| 
      
 11 
     | 
    
         
            +
                          instance_variable_set("@#{field}", value.dup)
         
     | 
| 
      
 12 
     | 
    
         
            +
                        else
         
     | 
| 
      
 13 
     | 
    
         
            +
                          instance_variable_set("@#{field}", value)
         
     | 
| 
      
 14 
     | 
    
         
            +
                        end
         
     | 
| 
      
 15 
     | 
    
         
            +
                      end
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                    self.attributes += fields
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
                def update_attributes(params = {})
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attributes = self.methods - Object.methods
         
     | 
| 
      
 23 
     | 
    
         
            +
                  params.each do |key, value|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    if attributes.member?((key.to_s + "=:").to_sym)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      self.send((key.to_s + "=:").to_sym, value)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                def attributes
         
     | 
| 
      
 31 
     | 
    
         
            +
                  self.class.attributes.inject({}) do |hash, attr|
         
     | 
| 
      
 32 
     | 
    
         
            +
                    hash[attr] = send(attr)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    hash
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MotionResource
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :id
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(params = {})
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @new_record = true
         
     | 
| 
      
 7 
     | 
    
         
            +
                  update_attributes(params)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                def new_record?
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @new_record
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def instantiate(json)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    raise ArgumentError, "No :id parameter given for #{self.name}.instantiate" unless json[:id]
         
     | 
| 
      
 17 
     | 
    
         
            +
                    
         
     | 
| 
      
 18 
     | 
    
         
            +
                    klass = if json[:type]
         
     | 
| 
      
 19 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 20 
     | 
    
         
            +
                        Object.const_get(json[:type].to_s)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      rescue NameError
         
     | 
| 
      
 22 
     | 
    
         
            +
                        self
         
     | 
| 
      
 23 
     | 
    
         
            +
                      end
         
     | 
| 
      
 24 
     | 
    
         
            +
                    else
         
     | 
| 
      
 25 
     | 
    
         
            +
                      self
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    
         
     | 
| 
      
 28 
     | 
    
         
            +
                    if result = klass.recall(json[:id])
         
     | 
| 
      
 29 
     | 
    
         
            +
                      result.update_attributes(json)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      result = klass.new(json)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      klass.remember(result.id, result)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                    result.send(:instance_variable_set, "@new_record", false)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    result
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  
         
     | 
| 
      
 38 
     | 
    
         
            +
                  def identity_map
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @identity_map ||= {}
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  
         
     | 
| 
      
 42 
     | 
    
         
            +
                  def remember(id, value)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    identity_map[id] = value
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  
         
     | 
| 
      
 46 
     | 
    
         
            +
                  def recall(id)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    identity_map[id]
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module MotionResource
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                def save(&block)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @new_record ? create(&block) : update(&block)
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                def update(&block)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  self.class.put(member_url, :payload => { self.class.name.underscore => attributes }) do |response, json|
         
     | 
| 
      
 9 
     | 
    
         
            +
                    block.call json.blank? ? nil : self.class.instantiate(json) if block
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
                def create(&block)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # weird heisenbug: Specs crash without that line :(
         
     | 
| 
      
 15 
     | 
    
         
            +
                  dummy = self
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.class.post(collection_url, :payload => { self.class.name.underscore => attributes }) do |response, json|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    block.call json.blank? ? nil : self.class.instantiate(json) if block
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
                def destroy(&block)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  self.class.delete(member_url) do |response, json|
         
     | 
| 
      
 23 
     | 
    
         
            +
                    block.call json.blank? ? nil : self.class.instantiate(json) if block
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
                def reload(&block)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  self.class.get(member_url) do |response, json|
         
     | 
| 
      
 29 
     | 
    
         
            +
                    block.call json.blank? ? nil : self.class.instantiate(json) if block
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     |