api_bee 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in api_bee.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec' # dev, test
8
+ end
9
+
data/README.mkd ADDED
@@ -0,0 +1,119 @@
1
+ # API BEE
2
+
3
+ API Bee is a small client / spec for a particular style of JSON API.
4
+
5
+ These APIs must
6
+
7
+ * Expose resource collections as paginated lists, with entries and paging properties.
8
+ * Resource entities in collections must include an 'href' property pointing to the individual resource, so as to provide a degree of discoverability.
9
+
10
+ A single resource might look like:
11
+
12
+ {
13
+ 'name': 'Foo',
14
+ 'description': 'foo resoruce',
15
+ 'href': 'http://api.myservice.com/resources/foo'
16
+ }
17
+
18
+ A resource collection looks like:
19
+
20
+ {
21
+ 'href': 'http://api.myservice.com/resources',
22
+ 'total_entries': 100,
23
+ 'page': 1,
24
+ 'per_page': 10,
25
+ 'entries': [
26
+ {
27
+ 'name': 'Foo',
28
+ 'description': 'foo resoruce',
29
+ 'href': 'http://api.myservice.com/resources/foo'
30
+ },
31
+ {
32
+ 'name': 'Bar',
33
+ 'description': 'bar resoruce',
34
+ 'href': 'http://api.myservice.com/resources/bar'
35
+ },
36
+ ...
37
+ ]
38
+ }
39
+
40
+ Collection resources must include the fields 'href', 'total_entries', 'page', 'per_page' and 'entries'. This allows clients to paginate and fetch more pages.
41
+
42
+ ## Adapters
43
+
44
+ It is up to individual adapters to talk to different services, handle auth, etc. An adapter must at least implement 'get' for read-only APIs.
45
+
46
+ ```ruby
47
+ class ApiBee::Adapters::Special
48
+ def get(path, options = {})
49
+ # fetch JSON from remote API, passing pagination options if available
50
+ end
51
+ end
52
+ ```
53
+
54
+ The use it:
55
+
56
+ ```ruby
57
+ api = ApiBee.setup :special, optional_custom_data
58
+
59
+ api.get('/my/resources').each do |r|
60
+ r[:name]
61
+ end
62
+ ```
63
+
64
+ ## Lazy loading
65
+
66
+ ApiBee wraps your adapters in lazy-loading objects. API calls will only be issued when accessing or iterating data.
67
+
68
+ The 'href' property in entities will be used to load more data. For example:
69
+
70
+ # /resources
71
+ [
72
+ {
73
+ 'title': 'Foo bar',
74
+ 'href': '/resources/foo-bar'
75
+ }
76
+ ]
77
+
78
+ # /resources/foo-bar
79
+ {
80
+ 'title': 'Foo bar',
81
+ 'description': 'Foo description'
82
+ }
83
+
84
+ ```ruby
85
+ api = ApiBee.get(:some_adapter)
86
+
87
+ resources = api.get('/resources') # no API call is made
88
+
89
+ resource = resources.first # call to /resources is made
90
+
91
+ resource['title'] # => 'Foo bar', title data available
92
+
93
+ resource['description'] # => 'Foo description'. Makes internal new request to /resources/foo-bar
94
+ ```
95
+
96
+
97
+ ## Hash adapter
98
+
99
+ ApiBee ships with an in-memory Hash adapter so it can be use with test/local data (for example a YAML file).
100
+
101
+ ```ruby
102
+ api = ApiBee.setup(:hash, YAML.load_file('./my_data.yml'))
103
+
104
+ products = api.get('/products') # => ApiBee::Node::List
105
+
106
+ products.first # => ApiBee::Node::Single
107
+
108
+ products.each() # iterate current page
109
+
110
+ products.current_page # => 1
111
+
112
+ products.paginate(:page => 2, :per_page => 4) # => ApiBee::Node::List # Next page
113
+
114
+ products.has_next_page? # => false
115
+
116
+ products.has_prev_page? # => true
117
+
118
+ products.prev_page # => 1
119
+ ```
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ # If you want to make this the default task
8
+ task :default => :spec
data/api_bee.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "api_bee/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "api_bee"
7
+ s.version = ApiBee::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ismael Celis"]
10
+ s.email = ["ismaelct@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Small Ruby client for discoverable, paginated JSON APIs}
13
+ s.description = %q{API Bee is a small client / spec for a particular style of JSON API. USe Hash adapter for local data access.}
14
+
15
+ s.rubyforge_project = "api_bee"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,61 @@
1
+ :products:
2
+ :total_entries: 6
3
+ :href: /products
4
+ :entries:
5
+ -
6
+ :title: P1
7
+ :id: p1
8
+ :price: 100
9
+ -
10
+ :title: P2
11
+ :id: p2
12
+ :price: 200
13
+ -
14
+ :title: P3
15
+ :id: p3
16
+ :price: 300
17
+ -
18
+ :title: P4
19
+ :id: p4
20
+ :price: 400
21
+ -
22
+ :title: P5
23
+ :id: p5
24
+ :price: 500
25
+ -
26
+ :title: P6
27
+ :id: p6
28
+ :price: 600
29
+
30
+ :collections:
31
+ :total_entries: 2
32
+ :href: /collections
33
+ :entries:
34
+ -
35
+ :title: Collection 1
36
+ :id: c1
37
+ :products:
38
+ :total_entries: 2
39
+ :page: 1
40
+ :per_page: 1
41
+ :href: /products
42
+ :entries:
43
+ -
44
+ :href: /products/p1
45
+ -
46
+ :href: /products/p2
47
+
48
+ -
49
+ :title: Collection 2
50
+ :id: c2
51
+ :products:
52
+ :total_entries: 2
53
+ :page: 1
54
+ :per_page: 1
55
+ :href: /products
56
+ :entries:
57
+ -
58
+ :href: /products/p1
59
+ -
60
+ :href: /products/p5
61
+
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH.unshift '../lib'
2
+ require 'yaml'
3
+ require 'api_bee'
4
+
5
+ api = ApiBee.setup(:hash, YAML.load_file('./catalog.yml'))
6
+
7
+ collection = api.get('/collections/c1')
8
+
9
+ p collection[:title]
10
+
11
+ products = collection[:products]
12
+
13
+ puts "First page"
14
+
15
+ products.each do |p|
16
+ p p[:title]
17
+ end
18
+
19
+ puts "Second page"
20
+
21
+ products.paginate(:page => products.next_page, :per_page => 2).each do |p|
22
+ p p[:title]
23
+ end
@@ -0,0 +1,72 @@
1
+ module ApiBee
2
+
3
+ module Adapters
4
+
5
+ class Hash
6
+
7
+ attr_reader :data
8
+
9
+ def initialize(*args)
10
+ @data = args.last
11
+ end
12
+
13
+ def get(href, opts = {})
14
+ segments = parse_href(href)
15
+ found = segments.inject(data) do |mem,i|
16
+ case mem
17
+ when ::Hash
18
+ handle_hash_data mem, i, opts
19
+ when ::Array
20
+ handle_array_data mem, i
21
+ else
22
+ mem
23
+ end
24
+ end
25
+ found
26
+ end
27
+
28
+ protected
29
+
30
+ def parse_href(href)
31
+ href.gsub(/^\//, '').split('/')
32
+ end
33
+
34
+ def handle_hash_data(hash, key, opts = {})
35
+ if is_paginated?(hash) # paginated collection
36
+ handle_array_data hash[:entries], key
37
+ else # /products. Might be a paginated list
38
+ r = hash[key.to_sym]
39
+ if opts.keys.include?(:page) && opts.keys.include?(:per_page) && r.kind_of?(::Hash) && is_paginated?(r)
40
+ paginate(r, opts[:page], opts[:per_page])
41
+ else
42
+ r
43
+ end
44
+ end
45
+ end
46
+
47
+ def handle_array_data(array, key)
48
+ if array[0].kind_of?(::Hash)
49
+ array.find {|e| e[:id] == key}
50
+ else
51
+ array
52
+ end
53
+ end
54
+
55
+ def is_paginated?(hash)
56
+ hash[ApiBee.config.uri_property_name] && hash[:total_entries]
57
+ end
58
+
59
+ def paginate(list, page, per_page)
60
+ from = page * per_page - per_page
61
+ to = page * per_page
62
+ list[:entries] = list[:entries].to_a[from...to]
63
+ list[:current_page] = page
64
+ list[:per_page] = per_page
65
+ list
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,140 @@
1
+ module ApiBee
2
+
3
+ class Node
4
+
5
+ def self.resolve(adapter, attrs)
6
+ keys = attrs.keys.map{|k| k.to_sym}
7
+ if keys.include?(:total_entries) && keys.include?(ApiBee.config.uri_property_name) # is a paginator
8
+ List.new adapter, attrs
9
+ else
10
+ Single.new adapter, attrs
11
+ end
12
+ end
13
+
14
+ attr_reader :adapter
15
+
16
+ def initialize(adapter, attrs)
17
+ @adapter = adapter
18
+ @attributes = {}
19
+ update_attributes attrs
20
+ end
21
+
22
+ def [](attribute_name)
23
+ if value = @attributes[attribute_name]
24
+ resolve_values_to_nodes value
25
+ elsif has_more? # check whether there's more info in API
26
+ load_more!
27
+ self[attribute_name] # recurse once
28
+ else
29
+ nil
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ def update_attributes(attrs)
36
+ @attributes.merge!(attrs)
37
+ end
38
+
39
+ def resolve_values_to_nodes(value)
40
+ case value
41
+ when ::Hash
42
+ Node.resolve @adapter, value
43
+ when ::Array
44
+ value.map {|v| resolve_values_to_nodes(v)} # recurse
45
+ else
46
+ value
47
+ end
48
+ end
49
+
50
+ def has_more?
51
+ !@complete && @attributes[ApiBee.config.uri_property_name]
52
+ end
53
+
54
+ def load_more!
55
+ more_data = @adapter.get(@attributes[ApiBee.config.uri_property_name])
56
+ update_attributes more_data if more_data
57
+ @complete = true
58
+ end
59
+
60
+ class Single < Node
61
+
62
+ end
63
+
64
+ class List < Node
65
+
66
+ DEFAULT_PER_PAGE = 100
67
+
68
+ def total_entries
69
+ @attributes[:total_entries].to_i
70
+ end
71
+
72
+ def size
73
+ entries.size
74
+ end
75
+
76
+ def current_page
77
+ (@attributes[:current_page] || 1).to_i
78
+ end
79
+
80
+ def per_page
81
+ (@attributes[:per_page] || DEFAULT_PER_PAGE).to_i
82
+ end
83
+
84
+ def total_pages
85
+ div = total_entries / per_page
86
+ div < 1 ? 1 : div
87
+ end
88
+
89
+ def next_page
90
+ current_page + 1
91
+ end
92
+
93
+ def prev_page
94
+ current_page - 1
95
+ end
96
+
97
+ def pages
98
+ (1..total_pages).to_a
99
+ end
100
+
101
+ def has_next_page?
102
+ next_page <= total_pages
103
+ end
104
+
105
+ def has_prev_page?
106
+ current_page > 1
107
+ end
108
+
109
+ def first
110
+ entries.first
111
+ end
112
+
113
+ def last
114
+ entries.last
115
+ end
116
+
117
+ def each(&block)
118
+ entries.each(&block)
119
+ end
120
+
121
+ def each_with_index(&block)
122
+ entries.each_with_index(&block)
123
+ end
124
+
125
+ def paginate(options = {})
126
+ data = @adapter.get(@attributes[ApiBee.config.uri_property_name], options)
127
+ Node.resolve @adapter, data
128
+ end
129
+
130
+ protected
131
+
132
+ def entries
133
+ @entries ||= (self[:entries] || [])
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+
140
+ end
@@ -0,0 +1,17 @@
1
+ module ApiBee
2
+
3
+ class Proxy
4
+
5
+ attr_reader :adapter
6
+
7
+ def initialize(adapter)
8
+ @adapter = adapter
9
+ end
10
+
11
+ def get(href)
12
+ Node.resolve @adapter, ApiBee.config.uri_property_name => href
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,3 @@
1
+ module ApiBee
2
+ VERSION = "0.0.1"
3
+ end
data/lib/api_bee.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'ostruct'
2
+ module ApiBee
3
+
4
+ class << ApiBee
5
+ attr_reader :config
6
+
7
+ def setup(adapter_klass, *args)
8
+
9
+ yield config if block_given?
10
+
11
+ adapter = if adapter_klass.is_a?(::Symbol)
12
+ require File.join('api_bee', 'adapters', adapter_klass.to_s)
13
+ klass = adapter_klass.to_s.gsub(/(^.{1})/){$1.upcase}
14
+ Adapters.const_get(klass).new(*args)
15
+ else
16
+ adapter_klass.new *args
17
+ end
18
+
19
+ raise NoMethodError, "Adapter must implement #get(path, *args) method" unless adapter.respond_to?(:get)
20
+ Proxy.new adapter
21
+ end
22
+
23
+ def config
24
+ @config ||= OpenStruct.new
25
+ end
26
+
27
+ end
28
+
29
+ # Defaults
30
+ self.config.uri_property_name = :href
31
+
32
+ module Adapters
33
+
34
+ end
35
+
36
+ end
37
+
38
+ require 'api_bee/proxy'
39
+ require 'api_bee/node'
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+ require 'api_bee/adapters/hash'
3
+
4
+ describe ApiBee::Adapters::Hash do
5
+
6
+ before do
7
+ @data = {
8
+ # Collections
9
+ :collections => [
10
+ {
11
+ :title => 'Catalog',
12
+ :id => 'catalog',
13
+ :foos => [1,2,3,4],
14
+ :products => {
15
+ :total_entries => 4,
16
+ :current_page => 1,
17
+ :per_page => 4,
18
+ :href => '/collections/catalog/products',
19
+ :entries => [
20
+ {
21
+ :id => 'foo-1',
22
+ :href => '/products/foo-1'
23
+ },
24
+ {
25
+ :id => 'foo-2',
26
+ :title => 'Foo 2',
27
+ :href => '/products/foo-2'
28
+ },
29
+ {
30
+ :id => 'foo-3',
31
+ :title => 'Foo 3',
32
+ :href => '/products/foo-3'
33
+ },
34
+ {
35
+ :id => 'foo-4',
36
+ :title => 'Foo 4',
37
+ :href => '/products/foo-4'
38
+ }
39
+ ]
40
+ }
41
+ }
42
+ ]
43
+ }
44
+
45
+ @adapter = ApiBee::Adapters::Hash.new(@data)
46
+ end
47
+
48
+ context 'accessing single nodes' do
49
+
50
+ before do
51
+ @collection = @adapter.get('/collections/catalog')
52
+ end
53
+
54
+ it 'should find node by :id' do
55
+ @collection[:title].should == 'Catalog'
56
+ @collection[:id].should == 'catalog'
57
+ end
58
+
59
+ it 'should find entries in paginated collections' do
60
+ product = @adapter.get('/collections/catalog/products/foo-2')
61
+ product[:title].should == 'Foo 2'
62
+ end
63
+
64
+ it 'should return whole collection if no pagination' do
65
+ products = @adapter.get('/collections/catalog/products')
66
+ # products.should == 1
67
+ products[:current_page].should == 1
68
+ products[:total_entries].should == 4
69
+ products[:per_page].should == 4
70
+ products[:entries].size.should == 4
71
+ end
72
+
73
+ it 'should paginate paginated collections' do
74
+ products = @adapter.get('/collections/catalog/products', :page => 2, :per_page => 2)
75
+ products[:current_page].should == 2
76
+ products[:total_entries].should == 4
77
+ products[:per_page].should == 2
78
+ products[:entries].size.should == 2
79
+ products[:entries][0][:title].should == 'Foo 3'
80
+ products[:entries][1][:title].should == 'Foo 4'
81
+ end
82
+ end
83
+
84
+ context 'accessing node collections' do
85
+
86
+ before do
87
+ @list = @adapter.get('/collections/catalog/foos')
88
+ end
89
+
90
+ it 'should return array' do
91
+ @list.size.should == 4
92
+ @list.should == [1,2,3,4]
93
+ end
94
+ end
95
+
96
+ end
data/spec/node_spec.rb ADDED
@@ -0,0 +1,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApiBee do
4
+
5
+ before do
6
+ @data = {
7
+ # Products
8
+ :products => {
9
+ :href => '/products',
10
+ :total_entries => 6,
11
+ :entries => [
12
+ {
13
+ :title => 'Foo 1',
14
+ :id => 'foo-1',
15
+ :price => 100,
16
+ :description => 'Foo 1 desc'
17
+ },
18
+ {
19
+ :title => 'Foo 2',
20
+ :id => 'foo-2',
21
+ :price => 200,
22
+ :description => 'Foo 2 desc'
23
+ },
24
+ {
25
+ :title => 'Foo 3',
26
+ :id => 'foo-3',
27
+ :price => 300,
28
+ :description => 'Foo 3 desc'
29
+ },
30
+ {
31
+ :title => 'Foo 4',
32
+ :id => 'foo-4',
33
+ :price => 400,
34
+ :description => 'Foo 4 desc'
35
+ },
36
+ {
37
+ :title => 'Foo 5',
38
+ :id => 'foo-5',
39
+ :price => 500,
40
+ :description => 'Foo 5 desc'
41
+ },
42
+ {
43
+ :title => 'Foo 6',
44
+ :id => 'foo-6',
45
+ :price => 600,
46
+ :description => 'Foo 6 desc'
47
+ }
48
+ ]
49
+ },
50
+ # Collections
51
+ :collections => [
52
+ {
53
+ :title => 'Catalog',
54
+ :id => 'catalog',
55
+ :products => {
56
+ :href => '/products',
57
+ :total_entries => 4,
58
+ :current_page => 1,
59
+ :per_page => 2,
60
+ :href => '/products',
61
+ :entries => [
62
+ {
63
+ :id => 'foo-1',
64
+ :href => '/products/foo-1'
65
+ },
66
+ {
67
+ :id => 'foo-2',
68
+ :title => 'Foo 2',
69
+ :href => '/products/foo-2'
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ ]
75
+ }
76
+
77
+ end
78
+
79
+ describe '.resolve' do
80
+
81
+ before do
82
+ @adapter = mock('Adapter')
83
+ end
84
+
85
+ it 'should resolve single nodes' do
86
+ node = ApiBee::Node.resolve(@adapter, {:title => 'Blah', :foo => [1,2,3]})
87
+ node[:title].should == 'Blah'
88
+ node.adapter.should == @adapter
89
+ node.should be_kind_of(ApiBee::Node::Single)
90
+ end
91
+
92
+ it 'should resolve paginated lists' do
93
+ node = ApiBee::Node.resolve(@adapter, {:title => 'Blah', :total_entries => 4, :href => '/products'})
94
+ node.total_entries.should == 4
95
+ node.adapter.should == @adapter
96
+ node.should be_kind_of(ApiBee::Node::List)
97
+ end
98
+ end
99
+
100
+ context 'lazy loading' do
101
+ before do
102
+ require 'api_bee/adapters/hash'
103
+ @adapter = ApiBee::Adapters::Hash.new(@data)
104
+ ApiBee::Adapters::Hash.should_receive(:new).with(@data).and_return @adapter
105
+ @api = ApiBee.setup(:hash, @data)
106
+ end
107
+
108
+ it 'should return a Proxy' do
109
+ @api.should be_kind_of(ApiBee::Proxy)
110
+ end
111
+
112
+ describe 'single nodes' do
113
+ it 'should call adapter only when accessing needed attributes' do
114
+ hash = @data[:collections].last
115
+ @adapter.should_receive(:get).exactly(1).times.with('/collections/catalog').and_return hash
116
+ node = @api.get('/collections/catalog')
117
+ node[:title].should == 'Catalog'
118
+ node[:id].should == 'catalog'
119
+ end
120
+ end
121
+
122
+ describe 'paginated lists' do
123
+ before do
124
+ @collection = @api.get('/collections/catalog')
125
+ @products = @collection[:products]
126
+ end
127
+
128
+ it 'should have a paginator interface' do
129
+ @products.total_entries.should == 4
130
+ @products.size.should == 2
131
+ @products.total_pages.should == 2
132
+ @products.current_page.should == 1
133
+ @products.pages.should == [1,2]
134
+ @products.has_next_page?.should be_true
135
+ @products.has_prev_page?.should be_false
136
+ end
137
+
138
+ it 'should iterate the first page' do
139
+ titles = []
140
+ klasses = []
141
+ @products.each {|p| titles << p[:title]}
142
+ @products.each {|p| klasses << p.class}
143
+ klasses.should == [ApiBee::Node::Single, ApiBee::Node::Single]
144
+ titles.should == ['Foo 1', 'Foo 2']
145
+ @products.first[:title].should == 'Foo 1'
146
+ @products.last[:title].should == 'Foo 2'
147
+ end
148
+
149
+ it 'should navigate to the second page' do
150
+ @products = @products.paginate(:page => 2, :per_page => 2)
151
+ titles = []
152
+ klasses = []
153
+ @products.each {|p| titles << p[:title]}
154
+ @products.each {|p| klasses << p.class}
155
+ @products.current_page.should == 2
156
+ @products.total_entries.should == 6
157
+ @products.size.should == 2
158
+ klasses.should == [ApiBee::Node::Single, ApiBee::Node::Single]
159
+ titles.should == ['Foo 3', 'Foo 4']
160
+ @products.first[:title].should == 'Foo 3'
161
+ @products.last[:title].should == 'Foo 4'
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+
168
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ApiBee.setup' do
4
+
5
+ describe 'with bundled adapter' do
6
+
7
+ it 'should return a proxy to instantiated adapter' do
8
+ api = ApiBee.setup(:hash, {})
9
+ api.adapter.should be_kind_of(ApiBee::Adapters::Hash)
10
+ end
11
+ end
12
+
13
+ describe 'config block' do
14
+
15
+ it 'should have default uri_property_name field name' do
16
+ ApiBee.config.uri_property_name.should == :href
17
+ end
18
+
19
+ it 'should set global variables' do
20
+ api = ApiBee.setup(:hash, {}) do |config|
21
+ config.foo = 11
22
+ config.bar = 22
23
+ end
24
+
25
+ ApiBee.config.foo.should == 11
26
+ ApiBee.config.bar.should == 22
27
+ end
28
+ end
29
+
30
+ describe 'with custom adapter class' do
31
+ before do
32
+
33
+ class CustomAdapter
34
+ attr_reader :opts
35
+ def initialize(opts)
36
+ @opts = opts
37
+ end
38
+
39
+ def get(path, *args);end
40
+ end
41
+
42
+ end
43
+
44
+ it 'shoud instantiate adapter with options' do
45
+ api = ApiBee.setup(CustomAdapter, :one => 1)
46
+ api.adapter.should be_kind_of(CustomAdapter)
47
+ api.adapter.opts.should == {:one => 1}
48
+ end
49
+
50
+ end
51
+
52
+ describe 'with adapter without #get method' do
53
+ it 'should complain' do
54
+ lambda {
55
+ ApiBee.setup(String)
56
+ }.should raise_error("Adapter must implement #get(path, *args) method")
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ $TESTING = true
5
+
6
+ Bundler.setup(:default, :test)
7
+
8
+ $LOAD_PATH.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib'))
9
+
10
+ ENV['RACK_ENV'] = 'test'
11
+
12
+ require 'api_bee'
13
+
14
+ RSpec.configure do |config|
15
+ # some (optional) config here
16
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_bee
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Ismael Celis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-09-19 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: API Bee is a small client / spec for a particular style of JSON API. USe Hash adapter for local data access.
17
+ email:
18
+ - ismaelct@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - .gitignore
27
+ - .rspec
28
+ - Gemfile
29
+ - README.mkd
30
+ - Rakefile
31
+ - api_bee.gemspec
32
+ - examples/catalog.yml
33
+ - examples/yaml_catalog.rb
34
+ - lib/api_bee.rb
35
+ - lib/api_bee/adapters/hash.rb
36
+ - lib/api_bee/node.rb
37
+ - lib/api_bee/proxy.rb
38
+ - lib/api_bee/version.rb
39
+ - spec/hash_adapter_spec.rb
40
+ - spec/node_spec.rb
41
+ - spec/setup_spec.rb
42
+ - spec/spec_helper.rb
43
+ homepage: ""
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project: api_bee
66
+ rubygems_version: 1.8.6
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Small Ruby client for discoverable, paginated JSON APIs
70
+ test_files:
71
+ - spec/hash_adapter_spec.rb
72
+ - spec/node_spec.rb
73
+ - spec/setup_spec.rb
74
+ - spec/spec_helper.rb