restulicious 0.0.13
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 +18 -0
- data/Gemfile +5 -0
- data/LICENSE +22 -0
- data/README +0 -0
- data/README.md +29 -0
- data/Rakefile +12 -0
- data/lib/restulicious/attributes.rb +42 -0
- data/lib/restulicious/config.rb +13 -0
- data/lib/restulicious/connection.rb +24 -0
- data/lib/restulicious/coordinator.rb +97 -0
- data/lib/restulicious/parser.rb +33 -0
- data/lib/restulicious/query_interface.rb +55 -0
- data/lib/restulicious/query_methods.rb +55 -0
- data/lib/restulicious/version.rb +3 -0
- data/lib/restulicious.rb +23 -0
- data/restulicious.gemspec +25 -0
- data/test/support/dummy_class.rb +2 -0
- data/test/support/test_helper.rb +12 -0
- data/test/unit/attributes_test.rb +29 -0
- data/test/unit/config_test.rb +63 -0
- data/test/unit/connection_test.rb +11 -0
- data/test/unit/coordinator_test.rb +68 -0
- data/test/unit/query_interface_test.rb +78 -0
- data/test/unit/query_methods_test.rb +63 -0
- metadata +175 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Tim Payton
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# RestResource
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rest_resource'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rest_resource
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Restulicious
|
2
|
+
module Attributes
|
3
|
+
extend ::ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def attributes(*attribute_names)
|
8
|
+
@attribute_names = attribute_names
|
9
|
+
attr_accessor *attribute_names
|
10
|
+
end
|
11
|
+
|
12
|
+
def attribute_names
|
13
|
+
@attribute_names
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(attributes = {})
|
19
|
+
self.class.attribute_names.each do |attr_name|
|
20
|
+
instance_variable_set("@#{attr_name}", check_utf8(attributes[attr_name]))
|
21
|
+
end
|
22
|
+
super(attributes)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def check_utf8(x)
|
28
|
+
return x unless x.is_a?(String)
|
29
|
+
return x if x.ascii_only?
|
30
|
+
enc_name = x.encoding.name
|
31
|
+
enc_valid = x.valid_encoding?
|
32
|
+
return x if enc_name == "UTF-8" && enc_valid
|
33
|
+
begin
|
34
|
+
puts "ENCODING #{enc_name} valid=#{enc_valid} for #{x}"
|
35
|
+
rescue Exception
|
36
|
+
puts "could not print attribute value"
|
37
|
+
end
|
38
|
+
x
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Restulicious
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
def get(url, params)
|
5
|
+
request = ::Typhoeus::Request.new(url,
|
6
|
+
method: :get,
|
7
|
+
headers: { Accept: "application/json" },
|
8
|
+
timeout: 100000, # milliseconds
|
9
|
+
cache_timeout: 60, # seconds
|
10
|
+
params: params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def post(url, params)
|
14
|
+
request = ::Typhoeus::Request.new(url,
|
15
|
+
method: :post,
|
16
|
+
headers: { Accept: "application/json" },
|
17
|
+
timeout: 100000, # milliseconds
|
18
|
+
cache_timeout: 60, # seconds
|
19
|
+
body: params.to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Restulicious
|
2
|
+
class Coordinator
|
3
|
+
|
4
|
+
def initialize(klazz)
|
5
|
+
@klazz = klazz
|
6
|
+
@after_complete_methods = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def query_interface
|
10
|
+
@query_interface ||= Restulicious::QueryInterface.new(@url)
|
11
|
+
end
|
12
|
+
|
13
|
+
def where(*args)
|
14
|
+
query_interface.where(*args)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def from(*args)
|
19
|
+
query_interface.from(*args)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def limit(*args)
|
24
|
+
query_interface.limit(*args)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def offset(*args)
|
29
|
+
query_interface.offset(*args)
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def select(*args)
|
34
|
+
query_interface.select(*args)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def includes(*args)
|
39
|
+
@after_complete_methods = args
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def first
|
44
|
+
@request = connection.get(query_interface.first_url, query_interface.params)
|
45
|
+
hydra.queue(@request)
|
46
|
+
hydra.run
|
47
|
+
parse.first
|
48
|
+
end
|
49
|
+
|
50
|
+
def all
|
51
|
+
@request = connection.get(query_interface.all_url, query_interface.params)
|
52
|
+
hydra.queue(@request)
|
53
|
+
hydra.run
|
54
|
+
parse
|
55
|
+
end
|
56
|
+
|
57
|
+
def create
|
58
|
+
@request = connection.post(query_interface.all_url, query_interface.params)
|
59
|
+
hydra.queue(@request)
|
60
|
+
hydra.run
|
61
|
+
# parse
|
62
|
+
end
|
63
|
+
|
64
|
+
def api_options(options)
|
65
|
+
@url = options[:url]
|
66
|
+
@type = options[:type]
|
67
|
+
@key = options[:key]
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def connection
|
73
|
+
Restulicious.config.connection_class.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def parser
|
77
|
+
Restulicious.config.parser_class.new(@klazz, key, @request.response.body)
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse
|
81
|
+
objects = parser.objects
|
82
|
+
@after_complete_methods.each do |name|
|
83
|
+
@klazz.send("after_api_complete_#{name}", objects)
|
84
|
+
end
|
85
|
+
objects
|
86
|
+
end
|
87
|
+
|
88
|
+
def hydra
|
89
|
+
Restulicious.config.hydra
|
90
|
+
end
|
91
|
+
|
92
|
+
def key
|
93
|
+
@key || @klazz.to_s.downcase.pluralize
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Restulicious
|
2
|
+
class Parser
|
3
|
+
|
4
|
+
def initialize(klazz, key, body)
|
5
|
+
@klazz = klazz
|
6
|
+
@key = key
|
7
|
+
@body = body
|
8
|
+
end
|
9
|
+
|
10
|
+
def objects
|
11
|
+
objects = []
|
12
|
+
if collection?
|
13
|
+
hashified_body[@key].each do |object_attributes|
|
14
|
+
objects << @klazz.from_api(object_attributes.symbolize_keys!)
|
15
|
+
end
|
16
|
+
else
|
17
|
+
objects << @klazz.from_api(hashified_body.symbolize_keys!)
|
18
|
+
end
|
19
|
+
objects
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def hashified_body
|
25
|
+
@hashified_body ||= JSON.parse(@body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def collection?
|
29
|
+
hashified_body[@key].is_a?(Array)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Restulicious
|
2
|
+
class QueryInterface
|
3
|
+
|
4
|
+
attr_reader :params
|
5
|
+
|
6
|
+
def initialize(url)
|
7
|
+
@url = url
|
8
|
+
@params = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def where(params)
|
12
|
+
@params.merge!(params)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def from(url)
|
17
|
+
@url = url
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def limit(limit)
|
22
|
+
@params[:limit] = limit
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def offset(offset)
|
27
|
+
@params[:offset] = offset
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def select(fields)
|
32
|
+
@params[:fields] = fields
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def all_url
|
37
|
+
interpolated_url
|
38
|
+
end
|
39
|
+
|
40
|
+
def first_url
|
41
|
+
[interpolated_url, @params[:id]].compact.join("/")
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def interpolated_url
|
47
|
+
interpolated_url = @url
|
48
|
+
@params.each do |key, value|
|
49
|
+
interpolated_url = interpolated_url.gsub /:#{key}/, value.to_s
|
50
|
+
end
|
51
|
+
interpolated_url
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Restulicious
|
2
|
+
module QueryMethods
|
3
|
+
extend ::ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def where(params)
|
8
|
+
coordinator.where(params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def from(url)
|
12
|
+
coordinator.from(url)
|
13
|
+
end
|
14
|
+
|
15
|
+
def limit(limit)
|
16
|
+
coordinator.limit(limit)
|
17
|
+
end
|
18
|
+
|
19
|
+
def offset(offset)
|
20
|
+
coordinator.offset(offset)
|
21
|
+
end
|
22
|
+
|
23
|
+
def select(fields)
|
24
|
+
coordinator.select(fields)
|
25
|
+
end
|
26
|
+
|
27
|
+
def includes(*args)
|
28
|
+
coordinator.includes(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def first
|
32
|
+
coordinator.first
|
33
|
+
end
|
34
|
+
|
35
|
+
def all
|
36
|
+
coordinator.all
|
37
|
+
end
|
38
|
+
|
39
|
+
def create
|
40
|
+
coordinator.create
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def api_options(options)
|
46
|
+
coordinator.api_options(options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def coordinator
|
50
|
+
@coordinator ||= Restulicious::Coordinator.new(self)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/restulicious.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'typhoeus'
|
2
|
+
require 'json'
|
3
|
+
require "restulicious/version"
|
4
|
+
require 'active_support/all'
|
5
|
+
|
6
|
+
module Restulicious
|
7
|
+
autoload :Attributes, "restulicious/attributes"
|
8
|
+
autoload :QueryMethods, "restulicious/query_methods"
|
9
|
+
autoload :QueryInterface, "restulicious/query_interface"
|
10
|
+
autoload :Config, "restulicious/config"
|
11
|
+
autoload :Coordinator, "restulicious/coordinator"
|
12
|
+
autoload :Connection, "restulicious/connection"
|
13
|
+
autoload :Parser, "restulicious/parser"
|
14
|
+
|
15
|
+
def self.config
|
16
|
+
@config ||= Config.new
|
17
|
+
if block_given?
|
18
|
+
yield @config
|
19
|
+
else
|
20
|
+
@config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/restulicious/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Tim Payton"]
|
6
|
+
gem.email = ["timpayton@gmail.com"]
|
7
|
+
gem.description = %q{Simplifies consumption of restful APIs, including a query interface like ActiveRecord. }
|
8
|
+
gem.summary = %q{Simplifies consumption of restful APIs, including a query interface like ActiveRecord. }
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "restulicious"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Restulicious::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency('activesupport', '>= 3.0.0')
|
19
|
+
gem.add_dependency('i18n')
|
20
|
+
gem.add_dependency('typhoeus')
|
21
|
+
|
22
|
+
gem.add_development_dependency('minitest', '>= 3.0.0')
|
23
|
+
gem.add_development_dependency('mocha')
|
24
|
+
gem.add_development_dependency('rake')
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# require 'rubygems'
|
2
|
+
# require 'bundler'
|
3
|
+
# Bundler.setup
|
4
|
+
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'mocha'
|
7
|
+
require 'restulicious'
|
8
|
+
|
9
|
+
# Load support files
|
10
|
+
Dir["#{File.dirname(__FILE__)}/**/*.rb"].each { |f| require f }
|
11
|
+
|
12
|
+
Mocha::Configuration.prevent(:stubbing_non_existent_method)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path('../../support/test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Restulicious::Attributes do
|
4
|
+
|
5
|
+
before do
|
6
|
+
DummyClass.send(:include, Restulicious::Attributes)
|
7
|
+
DummyClass.attributes(:id, :name)
|
8
|
+
|
9
|
+
@object = DummyClass.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "provides getter for declared attributes" do
|
13
|
+
assert_nil @object.id
|
14
|
+
end
|
15
|
+
|
16
|
+
it "provides setter for declared attributes" do
|
17
|
+
@object.id = 123
|
18
|
+
assert_equal 123, @object.id
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets attributes from hash passed to new" do
|
22
|
+
object = DummyClass.new(id: 1234)
|
23
|
+
assert_equal 1234, object.id
|
24
|
+
end
|
25
|
+
|
26
|
+
it "checks utf8 encoding"
|
27
|
+
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path('../../support/test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Restulicious::Config do
|
4
|
+
describe "with block" do
|
5
|
+
it "has defaults" do
|
6
|
+
Restulicious.config {}
|
7
|
+
assert_kind_of Typhoeus::Hydra, Restulicious.config.hydra
|
8
|
+
assert_equal Restulicious::Parser, Restulicious.config.parser_class
|
9
|
+
assert_equal Restulicious::Connection, Restulicious.config.connection_class
|
10
|
+
end
|
11
|
+
|
12
|
+
it "set options overrides defaults" do
|
13
|
+
Restulicious.config do |config|
|
14
|
+
config.connection_class = "boo"
|
15
|
+
config.hydra = "yah"
|
16
|
+
config.parser_class = "w00t"
|
17
|
+
end
|
18
|
+
assert_equal "boo", Restulicious.config.connection_class
|
19
|
+
assert_equal "yah", Restulicious.config.hydra
|
20
|
+
assert_equal "w00t", Restulicious.config.parser_class
|
21
|
+
end
|
22
|
+
|
23
|
+
it "set 1 option, other defaults remain" do
|
24
|
+
Restulicious.config do |config|
|
25
|
+
config.connection_class = "boo"
|
26
|
+
end
|
27
|
+
assert_equal "boo", Restulicious.config.connection_class
|
28
|
+
assert_kind_of Typhoeus::Hydra, Restulicious.config.hydra
|
29
|
+
assert_equal Restulicious::Parser, Restulicious.config.parser_class
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "without block" do
|
35
|
+
it "has defaults" do
|
36
|
+
assert_kind_of Typhoeus::Hydra, Restulicious.config.hydra
|
37
|
+
assert_equal Restulicious::Parser, Restulicious.config.parser_class
|
38
|
+
assert_equal Restulicious::Connection, Restulicious.config.connection_class
|
39
|
+
end
|
40
|
+
|
41
|
+
it "set options overrides defaults" do
|
42
|
+
Restulicious.config.connection_class = "boo"
|
43
|
+
Restulicious.config.hydra = "yah"
|
44
|
+
Restulicious.config.parser_class = "w00t"
|
45
|
+
assert_equal "boo", Restulicious.config.connection_class
|
46
|
+
assert_equal "yah", Restulicious.config.hydra
|
47
|
+
assert_equal "w00t", Restulicious.config.parser_class
|
48
|
+
end
|
49
|
+
|
50
|
+
it "set 1 option, other defaults remain" do
|
51
|
+
Restulicious.config.connection_class = "boo"
|
52
|
+
assert_equal "boo", Restulicious.config.connection_class
|
53
|
+
assert_kind_of Typhoeus::Hydra, Restulicious.config.hydra
|
54
|
+
assert_equal Restulicious::Parser, Restulicious.config.parser_class
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
after do
|
59
|
+
Restulicious.instance_variable_set(:@config, Restulicious::Config.new)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path('../../support/test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Restulicious::Coordinator do
|
4
|
+
describe "Interface" do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@coordinator = Restulicious::Coordinator.new(Class.new)
|
8
|
+
@coordinator.instance_variable_set(:@url, "www.example.com")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "has where method, which sends to interface" do
|
12
|
+
Restulicious::QueryInterface.any_instance.expects(:where).with(id: 5)
|
13
|
+
@coordinator.where(id: 5)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "has from method, which sends to interface" do
|
17
|
+
Restulicious::QueryInterface.any_instance.expects(:from).with("www.awesome.com/url/you/love")
|
18
|
+
@coordinator.from("www.awesome.com/url/you/love")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "has limit method, which sends to interface" do
|
22
|
+
Restulicious::QueryInterface.any_instance.expects(:limit).with(10)
|
23
|
+
@coordinator.limit(10)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "has offset method, which sends to interface" do
|
27
|
+
Restulicious::QueryInterface.any_instance.expects(:offset).with(10)
|
28
|
+
@coordinator.offset(10)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "has select method which sends to interface" do
|
32
|
+
Restulicious::QueryInterface.any_instance.expects(:select).with("id,name")
|
33
|
+
@coordinator.select("id,name")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "uses the same query interface each time" do
|
37
|
+
assert_equal @coordinator.query_interface, @coordinator.query_interface
|
38
|
+
end
|
39
|
+
|
40
|
+
it "has api_options method, that stores url" do
|
41
|
+
url = "http://www.example.com"
|
42
|
+
@coordinator.api_options(url: url)
|
43
|
+
assert_equal url, @coordinator.instance_variable_get(:@url)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "passes url along to query interface" do
|
47
|
+
url = "http://www.example.com"
|
48
|
+
@coordinator.api_options(url: url)
|
49
|
+
Restulicious::QueryInterface.expects(:new).with(url)
|
50
|
+
|
51
|
+
@coordinator.query_interface
|
52
|
+
end
|
53
|
+
|
54
|
+
it "chains interface methods on coordinator" do
|
55
|
+
@coordinator.expects(:all)
|
56
|
+
@coordinator.from("www.what.com").offset(10).limit(100).where(id: 42).select("id,name").all
|
57
|
+
end
|
58
|
+
|
59
|
+
it "includes stores args in after_complete_methods" do
|
60
|
+
@coordinator.includes(:users, :comments)
|
61
|
+
assert_equal [:users, :comments], @coordinator.instance_variable_get(:@after_complete_methods)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "has first method"
|
65
|
+
it "has all method"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.expand_path('../../support/test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Restulicious::QueryInterface do
|
4
|
+
describe "Interface" do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@interface = Restulicious::QueryInterface.new("http://bigdeal.com/the/next/:thing")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "has params reader" do
|
11
|
+
params = { foo: "bar" }
|
12
|
+
@interface.instance_variable_set(:@params, params)
|
13
|
+
assert_equal params, @interface.params
|
14
|
+
end
|
15
|
+
|
16
|
+
it "stores url in @url for from" do
|
17
|
+
url = "http://twitter.com/rocks/and/stuff"
|
18
|
+
@interface.from(url)
|
19
|
+
assert_equal url, @interface.instance_variable_get(:@url)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "stores params in @params for where" do
|
23
|
+
params = {
|
24
|
+
id: 123,
|
25
|
+
stuff: "w00t"
|
26
|
+
}
|
27
|
+
@interface.where(params)
|
28
|
+
assert_equal params, @interface.instance_variable_get(:@params)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "stores limit in @params for limit" do
|
32
|
+
limit = 10
|
33
|
+
@interface.limit(limit)
|
34
|
+
assert_equal limit, @interface.instance_variable_get(:@params)[:limit]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "stores offest in @params for offset" do
|
38
|
+
offset = 100
|
39
|
+
@interface.offset(offset)
|
40
|
+
assert_equal offset, @interface.instance_variable_get(:@params)[:offset]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "stores fields in @params for select" do
|
44
|
+
fields = "id,name,gender"
|
45
|
+
@interface.select(fields)
|
46
|
+
assert_equal fields, @interface.instance_variable_get(:@params)[:fields]
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "all_url" do
|
50
|
+
it "does string interpolation" do
|
51
|
+
@interface.where(thing: "super")
|
52
|
+
assert_equal "http://bigdeal.com/the/next/super", @interface.all_url
|
53
|
+
end
|
54
|
+
|
55
|
+
it "uses full url" do
|
56
|
+
assert_equal "http://bigdeal.com/the/next/:thing", @interface.all_url
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "first_url" do
|
61
|
+
it "does string interpolation" do
|
62
|
+
@interface.where(thing: "super")
|
63
|
+
assert_equal "http://bigdeal.com/the/next/super", @interface.first_url
|
64
|
+
end
|
65
|
+
|
66
|
+
it "adds id" do
|
67
|
+
@interface.where(id: 123, thing: "super")
|
68
|
+
assert_equal "http://bigdeal.com/the/next/super/123", @interface.first_url
|
69
|
+
end
|
70
|
+
|
71
|
+
it "does not add trailing slash, without id" do
|
72
|
+
@interface.where(thing: "super")
|
73
|
+
assert_equal "http://bigdeal.com/the/next/super", @interface.first_url
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path('../../support/test_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Restulicious::QueryMethods do
|
4
|
+
|
5
|
+
before do
|
6
|
+
DummyClass.send(:include, Restulicious::QueryMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has where method, which sends to coordinator" do
|
10
|
+
Restulicious::Coordinator.any_instance.expects(:where).with(id: 5)
|
11
|
+
DummyClass.where(id: 5)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has from method, which sends to coordinator" do
|
15
|
+
Restulicious::Coordinator.any_instance.expects(:from).with("www.awesome.com/url/you/love")
|
16
|
+
DummyClass.from("www.awesome.com/url/you/love")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "has limit method, which sends to coordinator" do
|
20
|
+
Restulicious::Coordinator.any_instance.expects(:limit).with(10)
|
21
|
+
DummyClass.limit(10)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "has offset method, which sends to coordinator" do
|
25
|
+
Restulicious::Coordinator.any_instance.expects(:offset).with(10)
|
26
|
+
DummyClass.offset(10)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has select method which sends to coordinator" do
|
30
|
+
Restulicious::Coordinator.any_instance.expects(:select).with("id,name")
|
31
|
+
DummyClass.select("id,name")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "has first method, which sends to coordinator" do
|
35
|
+
Restulicious::Coordinator.any_instance.expects(:first)
|
36
|
+
DummyClass.first
|
37
|
+
end
|
38
|
+
|
39
|
+
it "has all method, which sends to coordinator" do
|
40
|
+
Restulicious::Coordinator.any_instance.expects(:all)
|
41
|
+
DummyClass.all
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
it "has api_options method, which sends to coordinator" do
|
46
|
+
options = {
|
47
|
+
url: "www.awesome.com/stuff"
|
48
|
+
}
|
49
|
+
Restulicious::Coordinator.any_instance.expects(:api_options).with(options)
|
50
|
+
DummyClass.send(:api_options, options)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "has includes method, which sends to coordinator" do
|
54
|
+
Restulicious::Coordinator.any_instance.expects(:includes).with(:user)
|
55
|
+
DummyClass.includes(:user)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "has includes method, that allows multiple arguments" do
|
59
|
+
Restulicious::Coordinator.any_instance.expects(:includes).with(:user, :comments)
|
60
|
+
DummyClass.includes(:user, :comments)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: restulicious
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.13
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Payton
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: i18n
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: typhoeus
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.0.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.0.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: mocha
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rake
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: ! 'Simplifies consumption of restful APIs, including a query interface
|
111
|
+
like ActiveRecord. '
|
112
|
+
email:
|
113
|
+
- timpayton@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE
|
121
|
+
- README
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- lib/restulicious.rb
|
125
|
+
- lib/restulicious/attributes.rb
|
126
|
+
- lib/restulicious/config.rb
|
127
|
+
- lib/restulicious/connection.rb
|
128
|
+
- lib/restulicious/coordinator.rb
|
129
|
+
- lib/restulicious/parser.rb
|
130
|
+
- lib/restulicious/query_interface.rb
|
131
|
+
- lib/restulicious/query_methods.rb
|
132
|
+
- lib/restulicious/version.rb
|
133
|
+
- restulicious.gemspec
|
134
|
+
- test/support/dummy_class.rb
|
135
|
+
- test/support/test_helper.rb
|
136
|
+
- test/unit/attributes_test.rb
|
137
|
+
- test/unit/config_test.rb
|
138
|
+
- test/unit/connection_test.rb
|
139
|
+
- test/unit/coordinator_test.rb
|
140
|
+
- test/unit/query_interface_test.rb
|
141
|
+
- test/unit/query_methods_test.rb
|
142
|
+
homepage: ''
|
143
|
+
licenses: []
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 1.8.24
|
163
|
+
signing_key:
|
164
|
+
specification_version: 3
|
165
|
+
summary: Simplifies consumption of restful APIs, including a query interface like
|
166
|
+
ActiveRecord.
|
167
|
+
test_files:
|
168
|
+
- test/support/dummy_class.rb
|
169
|
+
- test/support/test_helper.rb
|
170
|
+
- test/unit/attributes_test.rb
|
171
|
+
- test/unit/config_test.rb
|
172
|
+
- test/unit/connection_test.rb
|
173
|
+
- test/unit/coordinator_test.rb
|
174
|
+
- test/unit/query_interface_test.rb
|
175
|
+
- test/unit/query_methods_test.rb
|