tastyrb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/LICENSE +10 -0
  2. data/README.md +6 -0
  3. data/lib/tastyrb.rb +151 -0
  4. metadata +105 -0
data/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ Copyright © 2011, Dan Drinkard
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+ * Neither the name of Sunlight Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9
+
10
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ Tastyrb
2
+ =======
3
+
4
+ A thin wrapper for self-describing tastypie APIs
5
+
6
+ Docs will go here.
data/lib/tastyrb.rb ADDED
@@ -0,0 +1,151 @@
1
+ require 'httparty'
2
+ require 'hashie'
3
+ require 'json'
4
+ require 'uri'
5
+
6
+ module Tastyrb
7
+
8
+ class Client
9
+
10
+ module Connection
11
+ include HTTParty
12
+ end
13
+
14
+ attr_accessor :api_key, :api_key_param, :jsonp_callback, :word_separator, :limit
15
+ attr_reader :resources, :meta
16
+
17
+ def initialize(base_uri=nil, api_key=nil, jsonp_callback=nil)
18
+ @resources = []
19
+ @api_key = api_key
20
+ @api_key_param = 'api_key'
21
+ @jsonp_callback = jsonp_callback
22
+ @word_separator = '_'
23
+ set_base_uri(base_uri)
24
+ end
25
+
26
+ def base_uri=(uri)
27
+ set_base_uri(uri)
28
+ end
29
+
30
+ def base_uri
31
+ @base_uri
32
+ end
33
+
34
+ def base_uri_path
35
+ URI.parse(@base_uri).path
36
+ end
37
+
38
+ def get(method, options)
39
+ params = prepare_options options
40
+ if params[:callback]
41
+ Connection.format :plain
42
+ else
43
+ Connection.format :json
44
+ end
45
+
46
+ response = Connection.get "#{@base_uri}#{path_for(method)}", :query => params
47
+
48
+ if response.code == 200
49
+ # JSONP
50
+ return response.body if Connection.format == :plain
51
+
52
+ # JSON
53
+ result = JSON.parse(response.body)['objects']
54
+ meta = JSON.parse(response.body)['meta']
55
+ @meta = Response.new(meta)
56
+
57
+ if result.size == 0
58
+ raise ResponseCodeError, "404: No document found"
59
+ elsif result.size == 1 && (options.keys.join(' ') =~ /(^|[\s\b_])id(?=\b|__)(?!__(in|i?(contains|(starts|ends)with)))/) != nil
60
+ # if we asked for an item by id and only one was returned, return just the object,
61
+ # else return a list always
62
+ Response.new(result[0])
63
+ else
64
+ result.map {|object| Response.new(object)}
65
+ end
66
+ else
67
+ raise ResponseCodeError, "#{response.code}: #{response.body}"
68
+ end
69
+
70
+ end
71
+
72
+ def next
73
+ get_from_meta(meta.next)
74
+ end
75
+
76
+ def previous
77
+ get_from_meta(meta.previous)
78
+ end
79
+
80
+ private
81
+
82
+ def get_from_meta(uri)
83
+ path, params = uri.split('?')
84
+ params = Hash[*params.split(/[&=]/)]
85
+ params.delete('format')
86
+ get method_for(path), params
87
+ end
88
+
89
+ def method_for(path)
90
+ path.to_s.sub(base_uri_path, '').gsub('/', '__').gsub(@word_separator, '_')
91
+ end
92
+
93
+ def path_for(method)
94
+ method.to_s.gsub('__', '/').gsub('_', @word_separator)
95
+ end
96
+
97
+ def prepare_options(options)
98
+ options[:callback] = @jsonp_callback if @jsonp_callback
99
+ options[:limit] = @limit if @limit
100
+
101
+ if options[:callback] != nil
102
+ options[:format] = 'jsonp'
103
+ else
104
+ options[:format] = 'json'
105
+ end
106
+
107
+ options.merge @api_key_param.to_sym => @api_key
108
+ end
109
+
110
+ def set_base_uri(uri)
111
+ @base_uri = uri =~ /\/$/ ? uri : "#{uri}/"
112
+ redefine_resources!
113
+ end
114
+
115
+ def redefine_resources!
116
+ # a given base_uri has unique resources associated with it
117
+ # we map them dynamically to methods each time the url changes
118
+ #> c = Tastyrb::Client.new
119
+ #> c.base_uri='http://example.com/api/v1'
120
+ #> c.my__search__method(:keywords=>'foo')
121
+ if @base_uri
122
+ @resources.each do |resource|
123
+ (class << self; self; end).class_eval do
124
+ remove_method resource
125
+ end
126
+ end
127
+
128
+ resource_desc = Connection.get(@base_uri, :query=>{:format=>'json'})
129
+ @resources = resource_desc.parsed_response.map do |resource|
130
+ method_for(resource[0]).to_sym
131
+ end
132
+
133
+ @resources.each do |resource|
134
+ (class << self; self; end).class_eval do
135
+ define_method resource do |*args|
136
+ get(resource, args[0]||{})
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ class ResponseCodeError < RuntimeError
146
+ end
147
+
148
+ class Response < Hashie::Mash
149
+ end
150
+
151
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tastyrb
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Dan Drinkard
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-07-18 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: hashie
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 2
30
+ - 0
31
+ version: 0.2.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: httparty
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 5
44
+ - 2
45
+ version: 0.5.2
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: json
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 1
57
+ - 1
58
+ - 3
59
+ version: 1.1.3
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ description: Generic client for self-describing APIs built with django-tastypie.
63
+ email: dan.drinkard@gmail.com
64
+ executables: []
65
+
66
+ extensions: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ files:
71
+ - lib/tastyrb.rb
72
+ - README.md
73
+ - LICENSE
74
+ has_rdoc: true
75
+ homepage: http://github.com/dandrinkard/tastyrb/
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options: []
80
+
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ requirements: []
98
+
99
+ rubyforge_project:
100
+ rubygems_version: 1.3.6
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Generic client for self-describing APIs built with django-tastypie.
104
+ test_files: []
105
+