extended_her 0.5
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 +8 -0
 - data/.rspec +2 -0
 - data/.travis.yml +8 -0
 - data/CONTRIBUTING.md +26 -0
 - data/Gemfile +2 -0
 - data/LICENSE +7 -0
 - data/README.md +723 -0
 - data/Rakefile +11 -0
 - data/UPGRADE.md +32 -0
 - data/examples/twitter-oauth/Gemfile +13 -0
 - data/examples/twitter-oauth/app.rb +50 -0
 - data/examples/twitter-oauth/config.ru +5 -0
 - data/examples/twitter-oauth/views/index.haml +9 -0
 - data/examples/twitter-search/Gemfile +12 -0
 - data/examples/twitter-search/app.rb +55 -0
 - data/examples/twitter-search/config.ru +5 -0
 - data/examples/twitter-search/views/index.haml +9 -0
 - data/extended_her.gemspec +27 -0
 - data/lib/her.rb +23 -0
 - data/lib/her/api.rb +108 -0
 - data/lib/her/base.rb +17 -0
 - data/lib/her/collection.rb +12 -0
 - data/lib/her/errors.rb +5 -0
 - data/lib/her/exceptions/exception.rb +4 -0
 - data/lib/her/exceptions/record_invalid.rb +8 -0
 - data/lib/her/exceptions/record_not_found.rb +13 -0
 - data/lib/her/middleware.rb +9 -0
 - data/lib/her/middleware/accept_json.rb +15 -0
 - data/lib/her/middleware/first_level_parse_json.rb +34 -0
 - data/lib/her/middleware/second_level_parse_json.rb +28 -0
 - data/lib/her/model.rb +69 -0
 - data/lib/her/model/base.rb +7 -0
 - data/lib/her/model/hooks.rb +114 -0
 - data/lib/her/model/http.rb +284 -0
 - data/lib/her/model/introspection.rb +57 -0
 - data/lib/her/model/orm.rb +191 -0
 - data/lib/her/model/orm/comparison_methods.rb +20 -0
 - data/lib/her/model/orm/create_methods.rb +29 -0
 - data/lib/her/model/orm/destroy_methods.rb +53 -0
 - data/lib/her/model/orm/error_methods.rb +19 -0
 - data/lib/her/model/orm/fields_definition.rb +15 -0
 - data/lib/her/model/orm/find_methods.rb +46 -0
 - data/lib/her/model/orm/persistance_methods.rb +22 -0
 - data/lib/her/model/orm/relation_mapper.rb +21 -0
 - data/lib/her/model/orm/save_methods.rb +58 -0
 - data/lib/her/model/orm/serialization_methods.rb +28 -0
 - data/lib/her/model/orm/update_methods.rb +31 -0
 - data/lib/her/model/paths.rb +82 -0
 - data/lib/her/model/relationships.rb +191 -0
 - data/lib/her/paginated_collection.rb +20 -0
 - data/lib/her/relation.rb +94 -0
 - data/lib/her/version.rb +3 -0
 - data/spec/api_spec.rb +131 -0
 - data/spec/collection_spec.rb +26 -0
 - data/spec/middleware/accept_json_spec.rb +10 -0
 - data/spec/middleware/first_level_parse_json_spec.rb +42 -0
 - data/spec/middleware/second_level_parse_json_spec.rb +25 -0
 - data/spec/model/hooks_spec.rb +406 -0
 - data/spec/model/http_spec.rb +184 -0
 - data/spec/model/introspection_spec.rb +59 -0
 - data/spec/model/orm_spec.rb +552 -0
 - data/spec/model/paths_spec.rb +286 -0
 - data/spec/model/relationships_spec.rb +222 -0
 - data/spec/model_spec.rb +31 -0
 - data/spec/spec_helper.rb +46 -0
 - metadata +222 -0
 
    
        data/Rakefile
    ADDED
    
    
    
        data/UPGRADE.md
    ADDED
    
    | 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Upgrade Her
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Here is a list of backward-incompatible changes that were introduced while Her is pre-1.0. After reaching 1.0, it will follow the [Semantic Versioning](http://semver.org/) system.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## 0.2.4
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            * Her no longer includes default middleware when making HTTP requests. The user has now to define all the needed middleware. Before:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    Her::API.setup :url => "https://api.example.com" do |connection|
         
     | 
| 
      
 10 
     | 
    
         
            +
                      connection.insert(0, FaradayMiddle::OAuth)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              Now:
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    Her::API.setup :url => "https://api.example.com" do |connection|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      connection.use FaradayMiddle::OAuth
         
     | 
| 
      
 17 
     | 
    
         
            +
                      connection.use Her::Middleware::FirstLevelParseJSON
         
     | 
| 
      
 18 
     | 
    
         
            +
                      connection.use Faraday::Request::UrlEncoded
         
     | 
| 
      
 19 
     | 
    
         
            +
                      connection.use Faraday::Adapter::NetHttp
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            ## 0.2
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            * The default parser middleware has been replaced to treat first-level JSON data as the resource or collection data. Before it expected this:
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    { "data": { "id": 1, "name": "Foo" }, "errors": [] }
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
               Now it expects this (the `errors` key is not treated as resource data):
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    { "id": 1, "name": "Foo", "errors": [] }
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
               If you still want to get the old behavior, you can use `Her::Middleware::SecondLevelParseJSON` instead of `Her::Middleware::FirstLevelParseJSON` in your middleware stack.
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Create custom parser
         
     | 
| 
      
 2 
     | 
    
         
            +
            class TwitterParser < Faraday::Response::Middleware
         
     | 
| 
      
 3 
     | 
    
         
            +
              def on_complete(env)
         
     | 
| 
      
 4 
     | 
    
         
            +
                json = MultiJson.load(env[:body], :symbolize_keys => true)
         
     | 
| 
      
 5 
     | 
    
         
            +
                errors = [json.delete(:error)]
         
     | 
| 
      
 6 
     | 
    
         
            +
                env[:body] = {
         
     | 
| 
      
 7 
     | 
    
         
            +
                  :data => json,
         
     | 
| 
      
 8 
     | 
    
         
            +
                  :errors => errors,
         
     | 
| 
      
 9 
     | 
    
         
            +
                  :metadata => {},
         
     | 
| 
      
 10 
     | 
    
         
            +
                }
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # See https://dev.twitter.com/apps
         
     | 
| 
      
 15 
     | 
    
         
            +
            TWITTER_CREDENTIALS = {
         
     | 
| 
      
 16 
     | 
    
         
            +
              :consumer_key => "",
         
     | 
| 
      
 17 
     | 
    
         
            +
              :consumer_secret => "",
         
     | 
| 
      
 18 
     | 
    
         
            +
              :token => "",
         
     | 
| 
      
 19 
     | 
    
         
            +
              :token_secret => ""
         
     | 
| 
      
 20 
     | 
    
         
            +
            }
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # Initialize API
         
     | 
| 
      
 23 
     | 
    
         
            +
            Her::API.setup :url => "https://api.twitter.com/1/" do |builder|
         
     | 
| 
      
 24 
     | 
    
         
            +
              builder.use FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
         
     | 
| 
      
 25 
     | 
    
         
            +
              builder.use Faraday::Request::UrlEncoded
         
     | 
| 
      
 26 
     | 
    
         
            +
              builder.use TwitterParser
         
     | 
| 
      
 27 
     | 
    
         
            +
              builder.use Faraday::Adapter::NetHttp
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            # Define classes
         
     | 
| 
      
 31 
     | 
    
         
            +
            class Tweet
         
     | 
| 
      
 32 
     | 
    
         
            +
              include Her::Model
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def self.timeline
         
     | 
| 
      
 35 
     | 
    
         
            +
                get "/statuses/home_timeline.json"
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def self.mentions
         
     | 
| 
      
 39 
     | 
    
         
            +
                get "/statuses/mentions.json"
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              def username
         
     | 
| 
      
 43 
     | 
    
         
            +
                user[:screen_name]
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            get "/" do
         
     | 
| 
      
 48 
     | 
    
         
            +
              @tweets = Tweet.mentions
         
     | 
| 
      
 49 
     | 
    
         
            +
              haml :index
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Create custom parser
         
     | 
| 
      
 2 
     | 
    
         
            +
            class TwitterSearchParser < Faraday::Response::Middleware
         
     | 
| 
      
 3 
     | 
    
         
            +
              METADATA_KEYS = [:completed_in, :max_id, :max_id_str, :next_page, :page, :query, :refresh_url, :results_per_page, :since_id, :since_id_str]
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def on_complete(env)
         
     | 
| 
      
 6 
     | 
    
         
            +
                json = MultiJson.load(env[:body], :symbolize_keys => true)
         
     | 
| 
      
 7 
     | 
    
         
            +
                data = json.delete(:results)
         
     | 
| 
      
 8 
     | 
    
         
            +
                errors = [json.delete(:error)].compact
         
     | 
| 
      
 9 
     | 
    
         
            +
                env[:body] = {
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :data => data,
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :errors => errors,
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :metadata => json
         
     | 
| 
      
 13 
     | 
    
         
            +
                }
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            class MyCache < Hash
         
     | 
| 
      
 18 
     | 
    
         
            +
              def read(key)
         
     | 
| 
      
 19 
     | 
    
         
            +
                if cached = self[key]
         
     | 
| 
      
 20 
     | 
    
         
            +
                  Marshal.load(cached)
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def write(key, data)
         
     | 
| 
      
 25 
     | 
    
         
            +
                self[key] = Marshal.dump(data)
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              def fetch(key)
         
     | 
| 
      
 29 
     | 
    
         
            +
                read(key) || yield.tap { |data| write(key, data) }
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            $cache = MyCache.new
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            # Initialize API
         
     | 
| 
      
 36 
     | 
    
         
            +
            Her::API.setup :url => "http://search.twitter.com" do |connection|
         
     | 
| 
      
 37 
     | 
    
         
            +
              connection.use Faraday::Request::UrlEncoded
         
     | 
| 
      
 38 
     | 
    
         
            +
              connection.use FaradayMiddleware::Caching, $cache
         
     | 
| 
      
 39 
     | 
    
         
            +
              connection.use TwitterSearchParser
         
     | 
| 
      
 40 
     | 
    
         
            +
              connection.use Faraday::Adapter::NetHttp
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            # Define classes
         
     | 
| 
      
 44 
     | 
    
         
            +
            class Tweet
         
     | 
| 
      
 45 
     | 
    
         
            +
              include Her::Model
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              def self.search(query, attrs={})
         
     | 
| 
      
 48 
     | 
    
         
            +
                get("/search.json", attrs.merge(:q => query))
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            get "/" do
         
     | 
| 
      
 53 
     | 
    
         
            +
              @tweets = Tweet.search("justin bieber", :rpp => 30)
         
     | 
| 
      
 54 
     | 
    
         
            +
              haml :index
         
     | 
| 
      
 55 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.push File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'her/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.name        = 'extended_her'
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.version     = Her::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.authors     = ['Rémi Prévost', 'Gregory Eremin']
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.email       = ['remi@exomel.com']
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.homepage    = 'http://remiprev.github.com/her'
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.license     = 'MIT'
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.summary     = 'A simple Representational State Transfer-based Hypertext Transfer Protocol-powered Object Relational Mapper. Her?'
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.description = 'Her is an ORM that maps REST resources and collections to Ruby objects'
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              s.files         = `git ls-files`.split("\n")
         
     | 
| 
      
 16 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.require_paths = ["lib"]
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              s.add_development_dependency 'rake', '~> 10.0'
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.add_development_dependency 'rspec', '~> 2.12'
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_development_dependency 'mocha', '~> 0.13'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_runtime_dependency 'activesupport', '>= 3.0.0'
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.add_runtime_dependency 'faraday', '~> 0.8'
         
     | 
| 
      
 26 
     | 
    
         
            +
              s.add_runtime_dependency 'multi_json', '~> 1.5'
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/her.rb
    ADDED
    
    | 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'her/version'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'multi_json'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'faraday'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'active_support/inflector'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'active_support/core_ext/hash'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'her/exceptions/exception'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'her/exceptions/record_invalid'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'her/exceptions/record_not_found'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require 'her/model'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'her/relation'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'her/api'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require 'her/middleware'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'her/errors'
         
     | 
| 
      
 18 
     | 
    
         
            +
            require 'her/collection'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'her/paginated_collection'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'her/base'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            module Her
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/her/api.rb
    ADDED
    
    | 
         @@ -0,0 +1,108 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Her
         
     | 
| 
      
 2 
     | 
    
         
            +
              # This class is where all HTTP requests are made. Before using Her, you must configure it
         
     | 
| 
      
 3 
     | 
    
         
            +
              # so it knows where to make those requests. In Rails, this is usually done in `config/initializers/her.rb`:
         
     | 
| 
      
 4 
     | 
    
         
            +
              class API
         
     | 
| 
      
 5 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :base_uri, :connection, :options
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                # Setup a default API connection. Accepted arguments and options are the same as {API#setup}.
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self.setup(attrs={}, &block)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @@default_api = new
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @@default_api.setup(attrs, &block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                # Create a new API object. This is useful to create multiple APIs and use them with the `uses_api` method.
         
     | 
| 
      
 15 
     | 
    
         
            +
                # If your application uses only one API, you should use Her::API.setup to configure the default API
         
     | 
| 
      
 16 
     | 
    
         
            +
                #
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @example Setting up a new API
         
     | 
| 
      
 18 
     | 
    
         
            +
                #   api = Her::API.new :url => "https://api.example" do |connection|
         
     | 
| 
      
 19 
     | 
    
         
            +
                #     connection.use Faraday::Request::UrlEncoded
         
     | 
| 
      
 20 
     | 
    
         
            +
                #     connection.use Her::Middleware::DefaultParseJSON
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                #   class User
         
     | 
| 
      
 24 
     | 
    
         
            +
                #     uses_api api
         
     | 
| 
      
 25 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 26 
     | 
    
         
            +
                def initialize(*args, &blk)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  self.setup(*args, &blk)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                # Setup the API connection.
         
     | 
| 
      
 31 
     | 
    
         
            +
                #
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @param [Hash] attrs the Faraday options
         
     | 
| 
      
 33 
     | 
    
         
            +
                # @option attrs [String] :url The main HTTP API root (eg. `https://api.example.com`)
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @option attrs [String] :ssl A hash containing [SSL options](https://github.com/technoweenie/faraday/wiki/Setting-up-SSL-certificates)
         
     | 
| 
      
 35 
     | 
    
         
            +
                #
         
     | 
| 
      
 36 
     | 
    
         
            +
                # @return Faraday::Connection
         
     | 
| 
      
 37 
     | 
    
         
            +
                #
         
     | 
| 
      
 38 
     | 
    
         
            +
                # @example Setting up the default API connection
         
     | 
| 
      
 39 
     | 
    
         
            +
                #   Her::API.setup :url => "https://api.example"
         
     | 
| 
      
 40 
     | 
    
         
            +
                #
         
     | 
| 
      
 41 
     | 
    
         
            +
                # @example A custom middleware added to the default list
         
     | 
| 
      
 42 
     | 
    
         
            +
                #   class MyAuthentication < Faraday::Middleware
         
     | 
| 
      
 43 
     | 
    
         
            +
                #     def call(env)
         
     | 
| 
      
 44 
     | 
    
         
            +
                #       env[:request_headers]["X-API-Token"] = "bb2b2dd75413d32c1ac421d39e95b978d1819ff611f68fc2fdd5c8b9c7331192"
         
     | 
| 
      
 45 
     | 
    
         
            +
                #       @all.call(env)
         
     | 
| 
      
 46 
     | 
    
         
            +
                #     end
         
     | 
| 
      
 47 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 48 
     | 
    
         
            +
                #   Her::API.setup :url => "https://api.example.com" do |connection|
         
     | 
| 
      
 49 
     | 
    
         
            +
                #     connection.use Faraday::Request::UrlEncoded
         
     | 
| 
      
 50 
     | 
    
         
            +
                #     connection.use Her::Middleware::DefaultParseJSON
         
     | 
| 
      
 51 
     | 
    
         
            +
                #     connection.use Faraday::Adapter::NetHttp
         
     | 
| 
      
 52 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 53 
     | 
    
         
            +
                #
         
     | 
| 
      
 54 
     | 
    
         
            +
                # @example A custom parse middleware
         
     | 
| 
      
 55 
     | 
    
         
            +
                #   class MyCustomParser < Faraday::Response::Middleware
         
     | 
| 
      
 56 
     | 
    
         
            +
                #     def on_complete(env)
         
     | 
| 
      
 57 
     | 
    
         
            +
                #       json = JSON.parse(env[:body], :symbolize_names => true)
         
     | 
| 
      
 58 
     | 
    
         
            +
                #       errors = json.delete(:errors) || {}
         
     | 
| 
      
 59 
     | 
    
         
            +
                #       metadata = json.delete(:metadata) || []
         
     | 
| 
      
 60 
     | 
    
         
            +
                #       env[:body] = { :data => json, :errors => errors, :metadata => metadata }
         
     | 
| 
      
 61 
     | 
    
         
            +
                #     end
         
     | 
| 
      
 62 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 63 
     | 
    
         
            +
                #   Her::API.setup :url => "https://api.example.com" do |connection|
         
     | 
| 
      
 64 
     | 
    
         
            +
                #     connection.use Faraday::Request::UrlEncoded
         
     | 
| 
      
 65 
     | 
    
         
            +
                #     connection.use MyCustomParser
         
     | 
| 
      
 66 
     | 
    
         
            +
                #     connection.use Faraday::Adapter::NetHttp
         
     | 
| 
      
 67 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 68 
     | 
    
         
            +
                def setup(attrs={}, &blk)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  attrs[:url] = attrs.delete(:base_uri) if attrs.include?(:base_uri) # Support legacy :base_uri option
         
     | 
| 
      
 70 
     | 
    
         
            +
                  @base_uri = attrs[:url]
         
     | 
| 
      
 71 
     | 
    
         
            +
                  @options = attrs
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @connection = Faraday.new(@options) do |connection|
         
     | 
| 
      
 73 
     | 
    
         
            +
                    yield connection if block_given?
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  self
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                # Define a custom parsing procedure. The procedure is passed the response object and is
         
     | 
| 
      
 79 
     | 
    
         
            +
                # expected to return a hash with three keys: a main data Hash, an errors Hash
         
     | 
| 
      
 80 
     | 
    
         
            +
                # and a metadata Hash.
         
     | 
| 
      
 81 
     | 
    
         
            +
                #
         
     | 
| 
      
 82 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 83 
     | 
    
         
            +
                def request(attrs={})
         
     | 
| 
      
 84 
     | 
    
         
            +
                  method = attrs.delete(:_method)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  path = attrs.delete(:_path)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  headers = attrs.delete(:_headers)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  attrs.delete_if { |key, value| key.to_s =~ /^_/ } # Remove all internal parameters
         
     | 
| 
      
 88 
     | 
    
         
            +
                  response = @connection.send method do |request|
         
     | 
| 
      
 89 
     | 
    
         
            +
                    request.headers.merge!(headers) if headers
         
     | 
| 
      
 90 
     | 
    
         
            +
                    if method == :get
         
     | 
| 
      
 91 
     | 
    
         
            +
                      # For GET requests, treat additional parameters as querystring data
         
     | 
| 
      
 92 
     | 
    
         
            +
                      request.url path, attrs
         
     | 
| 
      
 93 
     | 
    
         
            +
                    else
         
     | 
| 
      
 94 
     | 
    
         
            +
                      # For POST, PUT and DELETE requests, treat additional parameters as request body
         
     | 
| 
      
 95 
     | 
    
         
            +
                      request.url path
         
     | 
| 
      
 96 
     | 
    
         
            +
                      request.body = attrs
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                  response.env[:body]
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                private
         
     | 
| 
      
 103 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 104 
     | 
    
         
            +
                def self.default_api(attrs={})
         
     | 
| 
      
 105 
     | 
    
         
            +
                  defined?(@@default_api) ? @@default_api : nil
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/her/base.rb
    ADDED
    
    | 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Her
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base # In case you prefer inheritance over mixins
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Model
         
     | 
| 
      
 4 
     | 
    
         
            +
                include ActiveModel::Conversion if defined?(ActiveModel)
         
     | 
| 
      
 5 
     | 
    
         
            +
                include ActiveModel::AttributeMethods if defined?(ActiveModel)
         
     | 
| 
      
 6 
     | 
    
         
            +
                extend ActiveModel::Naming if defined?(ActiveModel)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def inherited(klass)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    klass.root_element(klass.name.demodulize.underscore)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    klass.collection_path(klass.root_element.pluralize)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    klass.resource_path([klass.collection_path, '/:id'].join)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    klass.uses_api(Her::API.default_api)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/her/errors.rb
    ADDED
    
    
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Her
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RecordNotFound < Exception
         
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def one(model, id)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    new("Couldn't find #{model.name} with id=#{id}")
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def some(model, ids, found, looking_for)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    super("Couldn't find all #{model.name}s with IDs (#{ids.join(', ')}) (found #{found} results, but was looking for #{looking_for})")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     |