api_bee 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore 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