├── .github └── workflows │ └── build.yml ├── .gitignore ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── activeresource-response.gemspec ├── lib ├── active_resource_response.rb ├── active_resource_response │ ├── connection.rb │ ├── custom_methods.rb │ ├── http_mock.rb │ ├── http_response.rb │ ├── lint.rb │ ├── response_method.rb │ └── version.rb └── activeresource-response.rb └── test ├── active_resource_response_test.rb ├── fixtures ├── city.rb ├── country.rb ├── region.rb ├── status.rb └── street.rb ├── lint_test.rb └── test_helper.rb /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | test: 11 | name: Tests with Ruby ${{ matrix.ruby-version }} 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | ruby-version: 16 | - 3.1 17 | - 3.2 18 | - 3.3 19 | - 3.4 20 | steps: 21 | - uses: actions/checkout@v3 22 | - uses: ruby/setup-ruby@v1 23 | with: 24 | ruby-version: ${{ matrix.ruby-version }} 25 | bundler-cache: true 26 | - name: Run tests 27 | run: | 28 | bundle exec rake 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Igor Fedoronchuk. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ActiveResource-Response 2 | This gem adds the ability to access the HTTP response (`Net::HTTPResponse`) object from the result (either a single object or a collection) of an ActiveResource call (methods: `find`, `all`, `first`, `last`, `get`). 3 | 4 | #### Why Can It Be Used? 5 | This functionality can be used to easily implement pagination in a REST API, so that an ActiveResource client can navigate paginated results. 6 | 7 | #### How to Use? 8 | Add the dependency to your `Gemfile`: 9 | 10 | ```ruby 11 | gem "activeresource-response" 12 | ``` 13 | 14 | Open your ActiveResource class and add: 15 | 16 | ```ruby 17 | add_response_method :your_method_name 18 | ``` 19 | 20 | You can add the method to `ActiveResource::Base` to use it in all subclasses: 21 | 22 | ```ruby 23 | class ActiveResource::Base 24 | add_response_method :my_response 25 | end 26 | ``` 27 | 28 | You can remove the method from an ActiveResource subclass: 29 | 30 | ```ruby 31 | class Order < ActiveResource::Base 32 | remove_response_method 33 | end 34 | ``` 35 | 36 | ## Full Example of Usage with the Kaminari Gem 37 | 38 | ActiveResource Class: 39 | 40 | ```ruby 41 | class Order < ActiveResource::Base 42 | self.format = :json 43 | self.site = 'http://0.0.0.0:3000/' 44 | self.element_name = "order" 45 | add_response_method :http_response # Our new method for returned objects 46 | end 47 | ``` 48 | 49 | Server Side: 50 | 51 | ```ruby 52 | class OrdersController < ApplicationController 53 | def index 54 | @orders = Order.page(params[:page]).per(params[:per_page] || 10) # default 10 per page 55 | response.headers["X-total"] = @orders.total_count.to_s 56 | response.headers["X-offset"] = @orders.offset_value.to_s 57 | response.headers["X-limit"] = @orders.limit_value.to_s 58 | respond_with(@orders) 59 | end 60 | end 61 | ``` 62 | 63 | Client Side: 64 | 65 | ```ruby 66 | class OrdersController < ApplicationController 67 | def index 68 | orders = Order.all(params: params) 69 | @orders = Kaminari::PaginatableArray.new(orders, { 70 | limit: orders.http_response['X-limit'].to_i, 71 | offset: orders.http_response['X-offset'].to_i, 72 | total_count: orders.http_response['X-total'].to_i 73 | }) 74 | end 75 | end 76 | ``` 77 | 78 | ### Will_paginate Compatibility 79 | `will_paginate` has a slightly different API, so to populate the headers: 80 | 81 | ```ruby 82 | response.headers["X-total"] = @orders.total_entries.to_s 83 | response.headers["X-offset"] = @orders.offset.to_s 84 | response.headers["X-limit"] = @orders.per_page.to_s 85 | ``` 86 | 87 | On the API client side, you might also use `will_paginate`. In that case, you can just require `will_paginate/array` (e.g., in an initializer): 88 | 89 | ```ruby 90 | orders = Order.all(params: params) 91 | @orders = WillPaginate::Collection.create(params[:page] || 1, params[:per_page] || 10, orders.http_response['X-total'].to_i) do |pager| 92 | pager.replace orders 93 | end 94 | ``` 95 | 96 | ### Every Time an HTTP Connection is Invoked 97 | The ActiveResource connection object stores the HTTP response. You can access it with the `http_response` method. 98 | 99 | Example: 100 | 101 | ```ruby 102 | class Order < ActiveResource::Base 103 | self.site = 'http://0.0.0.0:3000/' 104 | self.element_name = "order" 105 | add_response_method :my_response # Our new method 106 | end 107 | 108 | orders = Order.all 109 | first_order = Order.find(1) 110 | # See Net::HTTPResponse#[] method 111 | orders.my_response['content-length'] 112 | # => "3831" 113 | first_order.my_response['content-length'] 114 | # => "260" 115 | # Connection also always has the last HTTP response object. To access it, use the http_response method: 116 | Order.connection.http_response.to_hash 117 | # => {"content-type"=>["application/json; charset=utf-8"], "x-ua-compatible"=>["IE=Edge"], "etag"=>["\"573cabd02b2f1f90405f7f4f77995fab\""], "cache-control"=>["max-age=0, private, must-revalidate"], "x-request-id"=>["2911c13a0c781044c474450ed789613d"], "x-runtime"=>["0.071018"], "content-length"=>["260"], "server"=>["WEBrick/1.3.1 (Ruby/1.9.2/2011-02-18)"], "date"=>["Sun, 19 Feb 2012 10:21:29 GMT"], "connection"=>["close"]} 118 | ``` 119 | 120 | ### Custom `get` Method 121 | You can access the response from the result of a custom `get` method. 122 | 123 | Example: 124 | 125 | ```ruby 126 | class Country < ActiveResource::Base 127 | self.site = 'http://0.0.0.0:3000/' 128 | add_response_method :http # Our new method 129 | end 130 | 131 | cities = Country.find(1).get(:cities) 132 | cities.http # Method from the Country class is available 133 | ``` 134 | 135 | ### Headers and Cookies Methods 136 | You can get cookies and headers from the response. 137 | 138 | Example: 139 | 140 | ```ruby 141 | class Country < ActiveResource::Base 142 | self.site = 'http://0.0.0.0:3000/' 143 | add_response_method :my_response # Our new method 144 | end 145 | 146 | countries = Country.all 147 | countries.my_response.headers 148 | 149 | # Collection with symbolized keys: 150 | # {:content_type=>["application/json; charset=utf-8"], :x_ua_compatible=>["IE=Edge"], ..., :set_cookie=>["bar=foo; path=/", "foo=bar; path=/"]} 151 | 152 | countries.my_response.cookies 153 | # => {"bar"=>"foo", "foo"=>"bar"} 154 | ``` 155 | 156 | ### Note About HTTP Response 157 | The HTTP response is an object of `Net::HTTPOK`, `Net::HTTPClientError`, or one of the other subclasses of the `Net::HTTPResponse` class. For more information, see the documentation: [Net::HTTPResponse](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTPResponse.html). 158 | 159 | ### Testing with ActiveResource::HttpMock 160 | Add this line to your test to patch `http_mock`: 161 | 162 | ```ruby 163 | require "active_resource_response/http_mock" 164 | ``` 165 | 166 | ### Contributing 167 | 1. Fork it 168 | 2. Create your feature branch (`git checkout -b my-new-feature`) 169 | 3. Commit your changes (`git commit -am 'Add some feature'`) 170 | 4. Push to the branch (`git push origin my-new-feature`) 171 | 5. Create a new Pull Request 172 | 173 | #### Please feel free to contact me if you have any questions: 174 | fedoronchuk(at)gmail.com 175 | 176 | 177 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | 3 | require 'rake' 4 | require 'rake/testtask' 5 | 6 | task :default => [:test_units] 7 | 8 | desc "Run basic tests" 9 | Rake::TestTask.new("test_units") { |t| 10 | t.pattern = 'test/*_test.rb' 11 | t.verbose = true 12 | t.warning = true 13 | } -------------------------------------------------------------------------------- /activeresource-response.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "active_resource_response/version" 4 | 5 | Gem::Specification.new do |s| 6 | 7 | s.name = "activeresource-response" 8 | s.version = ActiveResourceResponse::Version::VERSION 9 | s.authors = ["Igor Fedoronchuk"] 10 | s.email = ["fedoronchuk@gmail.com"] 11 | s.homepage = "https://github.com/didww/activeresource-response" 12 | s.summary = %q{activeresource extension} 13 | s.description = %q{This gem adds possibility to access http response object from result of ActiveResource::Base find method } 14 | s.license = 'MIT' 15 | 16 | s.add_runtime_dependency('activeresource', ['>= 6.1', '< 6.2']) 17 | s.add_dependency "jruby-openssl" if RUBY_PLATFORM == "java" 18 | s.add_development_dependency "minitest" 19 | s.add_development_dependency 'rake' 20 | s.add_development_dependency 'byebug' 21 | 22 | 23 | s.files = `git ls-files | sed '/.gitignore/d'`.split("\n") 24 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 25 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 26 | s.require_paths = ["lib"] 27 | end 28 | -------------------------------------------------------------------------------- /lib/active_resource_response.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | require 'cgi' 24 | require 'active_resource' 25 | require "active_resource_response/version" 26 | require "active_resource_response/http_response" 27 | require "active_resource_response/connection" 28 | require "active_resource_response/response_method" 29 | require "active_resource_response/custom_methods" 30 | ActiveResource::Connection.send :include, ActiveResourceResponse::Connection 31 | ActiveResource::Base.send :include, ActiveResourceResponse::ResponseMethod 32 | ActiveResource::Base.send :include, ActiveResourceResponse::CustomMethods 33 | -------------------------------------------------------------------------------- /lib/active_resource_response/connection.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | module ActiveResourceResponse 24 | module Connection 25 | def self.included(base) 26 | base.class_eval do 27 | alias_method :origin_handle_response, :handle_response 28 | 29 | def handle_response(response) 30 | begin 31 | origin_handle_response(response) 32 | rescue 33 | raise 34 | ensure 35 | response.extend HttpResponse 36 | self.http_response=(response) 37 | end 38 | end 39 | 40 | def http_response 41 | http_storage[:ActiveResourceResponse] 42 | end 43 | 44 | def http_response=(response) 45 | http_storage[:ActiveResourceResponse] = response 46 | end 47 | 48 | def http_storage 49 | Thread.current 50 | end 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/active_resource_response/custom_methods.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | module ActiveResourceResponse 24 | module CustomMethods 25 | extend ActiveSupport::Concern 26 | included do 27 | class << self 28 | 29 | alias :origin_get :get 30 | 31 | def get(custom_method_name, options = {}) 32 | result = self.origin_get(custom_method_name, options) 33 | if self.respond_to? :http_response_method 34 | result = self.wrap_result(result) 35 | end 36 | result 37 | end 38 | end 39 | end 40 | 41 | def get(custom_method_name, options = {}) 42 | result = super(custom_method_name, options) 43 | if self.class.respond_to? :http_response_method 44 | result = self.class.wrap_result(result) 45 | end 46 | result 47 | end 48 | 49 | 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/active_resource_response/http_mock.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | require 'active_resource/http_mock' 24 | 25 | module ActiveResourceResponse 26 | module HttpMock 27 | module Response 28 | #to avoid methods conflict with Net:HttpResponse and ActiveResource::Response (HttpMock) 29 | def self.included(base) 30 | base.class_eval do 31 | def to_hash 32 | Hash[@headers.map{|k, value| [k, Array.wrap(value)] } ] 33 | end 34 | 35 | remove_method :[] 36 | def [](key) 37 | @headers[key] 38 | end 39 | end 40 | end 41 | end 42 | end 43 | end 44 | 45 | ActiveResource::Response.send :include, ActiveResourceResponse::HttpMock::Response 46 | -------------------------------------------------------------------------------- /lib/active_resource_response/http_response.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | module ActiveResourceResponse 24 | module HttpResponse 25 | 26 | def headers 27 | unless defined? @_active_resource_response_headers 28 | @_active_resource_response_headers = symbolize_keys(to_hash) 29 | end 30 | @_active_resource_response_headers 31 | end 32 | 33 | def cookies 34 | unless defined? @_active_resource_response_cookies 35 | @_active_resource_response_cookies = (self.headers[:set_cookie] || {}).inject({}) do |out, cookie_str| 36 | CGI::Cookie::parse(cookie_str).each do |key, cookie| 37 | out[key] = cookie.value.first unless ['expires', 'path'].include? key 38 | end 39 | out 40 | end 41 | end 42 | @_active_resource_response_cookies 43 | end 44 | 45 | private 46 | def symbolize_keys(hash) 47 | hash.inject({}) do |out, (key, value)| 48 | out[key.gsub(/-/, '_').downcase.to_sym] = value 49 | out 50 | end 51 | end 52 | 53 | end 54 | end -------------------------------------------------------------------------------- /lib/active_resource_response/lint.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | 24 | module ActiveResourceResponse 25 | module Lint 26 | def to_key 27 | return nil unless persisted? 28 | super 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/active_resource_response/response_method.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | require 'delegate' 24 | module ActiveResourceResponse 25 | 26 | module ResponseMethod 27 | 28 | def self.included(base) 29 | base.extend ClassMethods 30 | end 31 | 32 | module ClassMethods 33 | 34 | def http_response 35 | connection.http_response 36 | end 37 | 38 | def add_response_method(method_name = :http_response) 39 | class_attribute :http_response_method 40 | self.http_response_method = method_name 41 | class << self 42 | alias :find_without_http_response :find 43 | 44 | def find(*arguments) 45 | result = find_without_http_response(*arguments) 46 | self.wrap_result(result) 47 | end 48 | end unless methods.include?(:find_without_http_response) 49 | end 50 | 51 | def remove_response_method 52 | class << self 53 | undef :find 54 | alias :find :find_without_http_response 55 | undef :find_without_http_response 56 | undef :http_response_method 57 | undef :http_response_method= 58 | end 59 | end 60 | 61 | def wrap_result(result) 62 | result = SimpleDelegator.new(result) if result.frozen? 63 | result.instance_variable_set(:@http_response, connection.http_response) 64 | result.singleton_class.send(:define_method, self.http_response_method) do 65 | @http_response 66 | end 67 | result 68 | end 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/active_resource_response/version.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | 24 | module ActiveResourceResponse 25 | module Version 26 | VERSION = "3.0.0" 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/activeresource-response.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | 24 | require 'active_resource_response' -------------------------------------------------------------------------------- /test/active_resource_response_test.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | require_relative 'test_helper' 24 | class ActiveResourceResponseTest < Minitest::Test 25 | 26 | 27 | def setup 28 | @country = {:country => {:id => 1, :name => "Ukraine", :iso=>"UA"}} 29 | @country_create_error = {:errors => {:base => ["country exists"]}} 30 | @city = {:city => {:id => 1, :name => "Odessa", :population => 2500000}} 31 | @region = {:region => {:id => 1, :name => "Odessa region", :population => 4500000}} 32 | @street = {:street => {:id => 1, :name => "Deribasovskaya", :population => 2300}} 33 | 34 | ActiveResource::HttpMock.respond_to do |mock| 35 | mock.get "/countries.json", {}, [@country].to_json, 200, {"X-total"=>'1'} 36 | mock.get "/regions.json", {}, [@region].to_json, 200, {"X-total"=>'1'} 37 | mock.get "/regions/1.json", {}, @region.to_json, 200, {"X-total"=>'1'} 38 | mock.get "/regions/population.json", {}, {:count => 45000000}.to_json, 200, {"X-total"=>'1'} 39 | mock.get "/regions/cities.json", {}, [@city].to_json, 200, {"X-total"=>'2'} 40 | mock.get "/countries/1/statuses.json", {}, nil, 404 41 | mock.get "/countries/1.json", {}, @country.to_json, 200, {"X-total"=>'1', 'Set-Cookie'=>['path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT; foo=bar; bar=foo']} 42 | mock.get "/countries/1/population.json", {}, {:count => 45000000}.to_json, 200, {"X-total"=>'1'} 43 | mock.post "/countries.json", {}, @country_create_error.to_json, 422, {"X-total"=>'1'} 44 | mock.get "/countries/1/cities.json", {}, [@city].to_json, 200, {"X-total"=>'1'} 45 | mock.get "/regions/1/cities.json", {}, [@city].to_json, 200, {"X-total"=>'1'} 46 | mock.get "/cities/1/population.json", {}, {:count => 2500000}.to_json, 200, {"X-total"=>'1'} 47 | mock.get "/cities/1.json", {}, @city.to_json, 200, {"X-total"=>'1'} 48 | mock.get "/cities.json", {}, [@city].to_json, 200, {"X-total"=>'1'} 49 | mock.get "/streets.json", {}, [@street].to_json, 200, {"X-total"=>'1'} 50 | mock.get "/streets/1/city.json", {}, @city.to_json, 200, {"X-total"=>'1'} 51 | mock.get "/streets/1.json", {}, @street.to_json, 200, {"X-total"=>'1'} 52 | end 53 | end 54 | 55 | 56 | def test_methods_appeared 57 | countries = Country.all 58 | assert countries.respond_to?(:http) 59 | assert countries.http.respond_to?(:cookies) 60 | assert countries.http.respond_to?(:headers) 61 | assert Country.respond_to?(:http_response) 62 | regions = Region.all 63 | assert regions.respond_to?(:http_response) 64 | end 65 | 66 | def test_get_headers_from_all 67 | countries = Country.all 68 | assert_kind_of Country, countries.first 69 | assert_equal "UA", countries.first.iso 70 | assert_equal countries.http.headers[:x_total].first.to_i, 1 71 | end 72 | 73 | 74 | def test_headers_from_custom 75 | cities = Region.get("cities") 76 | assert cities.respond_to?(:http_response) 77 | assert_equal cities.http_response.headers[:x_total].first.to_i, 2 78 | assert_equal cities.http_response['X-total'].to_i, 2 79 | population = Country.find(1).get("population") 80 | 81 | #immutable objects doing good 82 | some_numeric = 45000000 83 | assert_equal population['count'], some_numeric 84 | assert population.respond_to?(:http) 85 | assert !some_numeric.respond_to?(:http) 86 | 87 | assert_equal Country.connection.http_response.headers[:x_total].first.to_i, 1 88 | assert_equal Country.http_response.headers[:x_total].first.to_i, 1 89 | assert_equal Country.http_response['X-total'].to_i, 1 90 | cities = Country.find(1).get("cities") 91 | assert cities.respond_to?(:http), "Cities should respond to http" 92 | assert_equal cities.http.headers[:x_total].first.to_i, 1, "Cities total value should be 1" 93 | regions_population = Region.get("population") 94 | assert_equal regions_population['count'], 45000000 95 | cities = Region.find(1).get("cities") 96 | assert cities.respond_to?(:http_response) 97 | assert_equal cities.http_response.headers[:x_total], ['1'] 98 | end 99 | 100 | def test_methods_without_http 101 | cities = City.all 102 | assert_kind_of City, cities.first 103 | count = cities.first.get("population")['count'] 104 | assert_equal count.to_i, 2500000 105 | end 106 | 107 | def test_get_headers_from_find 108 | country = Country.find(1) 109 | assert_equal country.http.headers[:x_total], ['1'] 110 | end 111 | 112 | def test_get_headers_from_find_when_404_custom_get 113 | Country.find(1).get(:statuses) rescue nil 114 | assert_equal Country.http_response.code, 404 115 | end 116 | 117 | def test_get_headers_from_find_when_404_custom_prefix 118 | Status.all params: { country_id: 1 } 119 | assert_equal Status.http_response.code, 404 120 | end 121 | 122 | def test_get_cookies 123 | country = Country.find(1) 124 | assert_equal country.http.cookies['foo'], 'bar' 125 | assert_equal country.http.cookies['bar'], 'foo' 126 | #from class 127 | assert_equal Country.http_response.cookies['foo'], 'bar' 128 | assert_equal Country.http_response.cookies['bar'], 'foo' 129 | end 130 | 131 | def test_headers_after_exception 132 | country = Country.create(@country[:country]) 133 | assert_equal Country.http_response.headers[:x_total], ['1'] 134 | assert_equal Country.http_response.code, 422 135 | assert_equal country.errors.full_messages.count ,1 136 | assert_equal country.errors.count ,1 137 | end 138 | 139 | def test_remove_method 140 | street = Street.find(:first) 141 | assert !(street.respond_to?(ActiveResourceResponseBase.http_response_method)) 142 | city = Street.find(1).get('city') 143 | assert !(city.respond_to?(ActiveResourceResponseBase.http_response_method)) 144 | #test if all ok in base class 145 | country = Country.find(1) 146 | assert country.respond_to?(Country.http_response_method) 147 | region = Region.find(1) 148 | assert region.respond_to?(ActiveResourceResponseBase.http_response_method) 149 | end 150 | 151 | def test_model_naming_methods 152 | street = Country.find(1) 153 | assert street.class.respond_to?(:model_name) 154 | end 155 | 156 | end 157 | -------------------------------------------------------------------------------- /test/fixtures/city.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | 24 | class City < ActiveResource::Base 25 | self.site = "http://37s.sunrise.i:3000" 26 | end -------------------------------------------------------------------------------- /test/fixtures/country.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | 24 | class ActiveResourceResponseBase < ActiveResource::Base 25 | self.site = "http://37s.sunrise.i:3000" 26 | add_response_method :http_response 27 | end 28 | 29 | 30 | class Country < ActiveResourceResponseBase 31 | add_response_method :http 32 | end 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/fixtures/region.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | class Region < ActiveResourceResponseBase 24 | self.site = "http://37s.sunrise.i:3000" 25 | end -------------------------------------------------------------------------------- /test/fixtures/status.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | class Status < ActiveResourceResponseBase 24 | self.element_name = 'status' 25 | self.prefix += 'countries/:country_id/' 26 | end 27 | -------------------------------------------------------------------------------- /test/fixtures/street.rb: -------------------------------------------------------------------------------- 1 | class Street < ActiveResourceResponseBase 2 | remove_response_method 3 | end -------------------------------------------------------------------------------- /test/lint_test.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # Copyright (c) 2012 Igor Fedoronchuk 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining 5 | # a copy of this software and associated documentation files (the 6 | # "Software"), to deal in the Software without restriction, including 7 | # without limitation the rights to use, copy, modify, merge, publish, 8 | # distribute, sublicense, and/or sell copies of the Software, and to 9 | # permit persons to whom the Software is furnished to do so, subject to 10 | # the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be 13 | # included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | #++ 23 | 24 | require_relative 'test_helper' 25 | 26 | 27 | 28 | #made pass lint test because of "to_key should return nil when `persisted?` returns false" error 29 | require "active_resource_response/lint" 30 | ActiveResource::Base.send :include, ActiveResourceResponse::Lint 31 | 32 | class ActiveResourceResponseLintTest < Minitest::Test 33 | 34 | include ActiveModel::Lint::Tests 35 | 36 | def setup 37 | @street = {:street => {:id => 1, :name => "Deribasovskaya", :population => 2300}} 38 | ActiveResource::HttpMock.respond_to do |mock| 39 | mock.get "/streets/1.json", {}, @street.to_json, 200, {"X-total"=>'1'} 40 | end 41 | @model = Street.find(1) 42 | end 43 | 44 | 45 | 46 | end 47 | 48 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'i18n' 3 | lib = File.expand_path("#{File.dirname(__FILE__)}/../lib") 4 | unit_tests = File.expand_path("#{File.dirname(__FILE__)}/../test") 5 | $:.unshift(lib) 6 | $:.unshift(unit_tests) 7 | I18n.config.enforce_available_locales = true 8 | require 'active_resource_response' 9 | require "fixtures/country" 10 | require "fixtures/city" 11 | require "fixtures/region" 12 | require "fixtures/street" 13 | require "fixtures/status" 14 | require "active_resource_response/http_mock" --------------------------------------------------------------------------------