wordnik 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 +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +57 -0
- data/README.md +0 -0
- data/Rakefile +9 -0
- data/lib/wordnik.rb +33 -0
- data/lib/wordnik/configuration.rb +21 -0
- data/lib/wordnik/endpoint.rb +32 -0
- data/lib/wordnik/operation.rb +42 -0
- data/lib/wordnik/operation_parameter.rb +36 -0
- data/lib/wordnik/request.rb +159 -0
- data/lib/wordnik/resource.rb +50 -0
- data/lib/wordnik/response.rb +69 -0
- data/lib/wordnik/version.rb +3 -0
- data/spec/endpoint_spec.rb +26 -0
- data/spec/operation_parameter_spec.rb +26 -0
- data/spec/operation_spec.rb +37 -0
- data/spec/request_spec.rb +155 -0
- data/spec/resource_spec.rb +31 -0
- data/spec/response_spec.rb +49 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/wordnik_spec.rb +11 -0
- data/wordnik.gemspec +32 -0
- metadata +232 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
wordnik (0.0.1)
|
5
|
+
activemodel (= 3.0.3)
|
6
|
+
addressable (= 2.2.4)
|
7
|
+
htmlentities (= 4.2.4)
|
8
|
+
json (= 1.4.6)
|
9
|
+
nokogiri (= 1.4.4)
|
10
|
+
typhoeus (= 0.2.1)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: http://rubygems.org/
|
14
|
+
specs:
|
15
|
+
activemodel (3.0.3)
|
16
|
+
activesupport (= 3.0.3)
|
17
|
+
builder (~> 2.1.2)
|
18
|
+
i18n (~> 0.4)
|
19
|
+
activesupport (3.0.3)
|
20
|
+
addressable (2.2.4)
|
21
|
+
builder (2.1.2)
|
22
|
+
crack (0.1.8)
|
23
|
+
diff-lcs (1.1.2)
|
24
|
+
htmlentities (4.2.4)
|
25
|
+
i18n (0.5.0)
|
26
|
+
json (1.4.6)
|
27
|
+
mime-types (1.16)
|
28
|
+
nokogiri (1.4.4)
|
29
|
+
rspec (2.4.0)
|
30
|
+
rspec-core (~> 2.4.0)
|
31
|
+
rspec-expectations (~> 2.4.0)
|
32
|
+
rspec-mocks (~> 2.4.0)
|
33
|
+
rspec-core (2.4.0)
|
34
|
+
rspec-expectations (2.4.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.4.0)
|
37
|
+
typhoeus (0.2.1)
|
38
|
+
mime-types
|
39
|
+
vcr (1.5.1)
|
40
|
+
webmock (1.6.2)
|
41
|
+
addressable (>= 2.2.2)
|
42
|
+
crack (>= 0.1.7)
|
43
|
+
|
44
|
+
PLATFORMS
|
45
|
+
ruby
|
46
|
+
|
47
|
+
DEPENDENCIES
|
48
|
+
activemodel (= 3.0.3)
|
49
|
+
addressable (= 2.2.4)
|
50
|
+
htmlentities (= 4.2.4)
|
51
|
+
json (= 1.4.6)
|
52
|
+
nokogiri (= 1.4.4)
|
53
|
+
rspec (= 2.4.0)
|
54
|
+
typhoeus (= 0.2.1)
|
55
|
+
vcr (= 1.5.1)
|
56
|
+
webmock (= 1.6.2)
|
57
|
+
wordnik!
|
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
data/lib/wordnik.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'wordnik/endpoint'
|
2
|
+
require 'wordnik/operation'
|
3
|
+
require 'wordnik/operation_parameter'
|
4
|
+
require 'wordnik/request'
|
5
|
+
require 'wordnik/resource'
|
6
|
+
require 'wordnik/response'
|
7
|
+
require 'wordnik/configuration'
|
8
|
+
|
9
|
+
module Wordnik
|
10
|
+
|
11
|
+
API_VERSION = "4.01.61"
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
# A Wordnik configuration object. Must act like a hash and return sensible
|
16
|
+
# values for all Wordnik configuration options. See Wordnik::Configuration.
|
17
|
+
attr_accessor :configuration
|
18
|
+
|
19
|
+
# Call this method to modify defaults in your initializers.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# Wordnik.configure do |config|
|
23
|
+
# config.api_key = '1234567890abcdef'
|
24
|
+
# config.response_format = :json
|
25
|
+
# end
|
26
|
+
def configure
|
27
|
+
self.configuration ||= Configuration.new
|
28
|
+
yield(configuration) if block_given?
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Wordnik
|
2
|
+
|
3
|
+
class Configuration
|
4
|
+
|
5
|
+
# The API key for your project, found on the project edit form.
|
6
|
+
attr_accessor :api_key
|
7
|
+
|
8
|
+
# Response format can be :json (default) or :xml
|
9
|
+
attr_accessor :response_format
|
10
|
+
|
11
|
+
# The URL of the API server
|
12
|
+
attr_accessor :base_uri
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@response_format = :json
|
16
|
+
@base_uri = 'beta.wordnik.com/v4'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# To jog the memory: Resource > Endpoint > Operation > OperationParameter
|
2
|
+
require 'active_model'
|
3
|
+
|
4
|
+
class Endpoint
|
5
|
+
|
6
|
+
include ActiveModel::Validations
|
7
|
+
include ActiveModel::Conversion
|
8
|
+
extend ActiveModel::Naming
|
9
|
+
|
10
|
+
attr_accessor :path, :description, :operations
|
11
|
+
|
12
|
+
validates_presence_of :path, :description, :operations
|
13
|
+
|
14
|
+
def initialize(attributes = {})
|
15
|
+
attributes.each do |name, value|
|
16
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Generate Operations instances from JSON
|
20
|
+
if self.operations
|
21
|
+
self.operations = self.operations.map do |operationData|
|
22
|
+
Operation.new(operationData)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# It's an ActiveModel thing..
|
28
|
+
def persisted?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# To jog the memory: Resource > Endpoint > Operation > OperationParameter
|
2
|
+
|
3
|
+
class Operation
|
4
|
+
include ActiveModel::Validations
|
5
|
+
include ActiveModel::Conversion
|
6
|
+
extend ActiveModel::Naming
|
7
|
+
|
8
|
+
attr_accessor :http_method, :summary, :notes, :parameters, :response, :open
|
9
|
+
|
10
|
+
validates_presence_of :http_method, :summary, :notes, :parameters, :response, :open
|
11
|
+
|
12
|
+
def initialize(attributes = {})
|
13
|
+
attributes.each do |name, value|
|
14
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
15
|
+
end
|
16
|
+
|
17
|
+
self.http_method = self.http_method.to_s.downcase
|
18
|
+
|
19
|
+
# Generate OperationParameter instances from JSON
|
20
|
+
if self.parameters
|
21
|
+
self.parameters = self.parameters.map do |parameterData|
|
22
|
+
OperationParameter.new(parameterData)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def get?
|
29
|
+
self.http_method.downcase == "get"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Can this operation be run in the sandbox?
|
33
|
+
def sandboxable?
|
34
|
+
self.get?
|
35
|
+
end
|
36
|
+
|
37
|
+
# It's an ActiveModel thing..
|
38
|
+
def persisted?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# To jog the memory: Resource > Endpoint > Operation > OperationParameter
|
2
|
+
|
3
|
+
class OperationParameter
|
4
|
+
include ActiveModel::Validations
|
5
|
+
include ActiveModel::Conversion
|
6
|
+
extend ActiveModel::Naming
|
7
|
+
|
8
|
+
attr_accessor :name, :description, :required, :param_type, :default_value, :allowable_values
|
9
|
+
|
10
|
+
validates_presence_of :name, :description, :required, :param_type, :default_value, :allowable_values
|
11
|
+
|
12
|
+
def initialize(attributes = {})
|
13
|
+
attributes.each do |name, value|
|
14
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def human_name
|
19
|
+
return "request body" if self.param_type == 'body'
|
20
|
+
self.name
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_allowable_array?
|
24
|
+
self.allowable_values.present? && self.allowable_values.include?(",")
|
25
|
+
end
|
26
|
+
|
27
|
+
def required?
|
28
|
+
self.required
|
29
|
+
end
|
30
|
+
|
31
|
+
# It's an ActiveModel thing..
|
32
|
+
def persisted?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
class Request
|
2
|
+
require 'uri'
|
3
|
+
require 'addressable/uri'
|
4
|
+
require 'typhoeus'
|
5
|
+
include ActiveModel::Validations
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
|
9
|
+
attr_accessor :host, :port, :path, :format, :params, :body, :http_method, :headers
|
10
|
+
|
11
|
+
validates_presence_of :host, :path, :format, :http_method
|
12
|
+
|
13
|
+
def initialize(http_method, path, attributes={})
|
14
|
+
attributes[:format] ||= "json"
|
15
|
+
attributes[:host] ||= Wordnik.configuration.base_uri
|
16
|
+
attributes[:params] ||= {}
|
17
|
+
|
18
|
+
# Set default headers, but allow them to be overridden
|
19
|
+
default_headers = {
|
20
|
+
'Content-Type' => "application/#{attributes[:format].downcase}",
|
21
|
+
}
|
22
|
+
attributes[:headers] = default_headers.merge(attributes[:headers] || {})
|
23
|
+
|
24
|
+
self.http_method = http_method.to_sym
|
25
|
+
self.path = path
|
26
|
+
attributes.each do |name, value|
|
27
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Construct a base URL
|
32
|
+
def url
|
33
|
+
u = Addressable::URI.new
|
34
|
+
u.host = self.host.sub(/\/$/, '')
|
35
|
+
u.port = self.port if self.port.present?
|
36
|
+
u.path = self.interpreted_path
|
37
|
+
u.scheme = "http" # For some reason this must be set _after_ host, otherwise Addressable gets upset
|
38
|
+
u.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
# Iterate over the params hash, injecting any path values into the path string
|
42
|
+
# e.g. /word.{format}/{word}/entries => /word.json/cat/entries
|
43
|
+
def interpreted_path
|
44
|
+
p = self.path
|
45
|
+
self.params.each_pair do |key, value|
|
46
|
+
p = p.gsub("{#{key}}", value.to_s)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Stick a .{format} placeholder into the path if there isn't
|
50
|
+
# one already or an actual format like json or xml
|
51
|
+
# e.g. /words/blah => /words.{format}/blah
|
52
|
+
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
|
53
|
+
p = p.sub(/^(\/?\w+)/, "\\1.#{format}")
|
54
|
+
end
|
55
|
+
|
56
|
+
p = p.sub("{format}", self.format)
|
57
|
+
URI.encode(p)
|
58
|
+
end
|
59
|
+
|
60
|
+
def interpreted_body
|
61
|
+
return unless self.body.present?
|
62
|
+
return self.body.to_json if self.body.is_a?(Hash)
|
63
|
+
self.body
|
64
|
+
end
|
65
|
+
|
66
|
+
# Iterate over all params,
|
67
|
+
# .. removing the ones that are part of the path itself.
|
68
|
+
# .. stringifying values so Addressable doesn't blow up.
|
69
|
+
# .. obfuscating the API key if needed.
|
70
|
+
def query_string_params(obfuscated=false)
|
71
|
+
qsp = {}
|
72
|
+
self.params.each_pair do |key, value|
|
73
|
+
next if self.path.include? "{#{key}}"
|
74
|
+
next if value.blank?
|
75
|
+
value = "YOUR_API_KEY" if key.to_sym == :api_key && obfuscated
|
76
|
+
qsp[key] = value.to_s
|
77
|
+
end
|
78
|
+
qsp
|
79
|
+
end
|
80
|
+
|
81
|
+
# Construct a query string from the query-string-type params
|
82
|
+
def query_string(options={})
|
83
|
+
|
84
|
+
# We don't want to end up with '?' as our query string
|
85
|
+
# if there aren't really any params
|
86
|
+
return "" if query_string_params.blank?
|
87
|
+
|
88
|
+
default_options = {:obfuscated => false}
|
89
|
+
options = default_options.merge(options)
|
90
|
+
|
91
|
+
qs = Addressable::URI.new
|
92
|
+
qs.query_values = self.query_string_params(options[:obfuscated])
|
93
|
+
qs.to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns full request URL with query string included
|
97
|
+
def url_with_query_string(options={})
|
98
|
+
default_options = {:obfuscated => false}
|
99
|
+
options = default_options.merge(options)
|
100
|
+
|
101
|
+
[url, query_string(options)].join('')
|
102
|
+
end
|
103
|
+
|
104
|
+
def make
|
105
|
+
response = case self.http_method.to_sym
|
106
|
+
when :get
|
107
|
+
Typhoeus::Request.get(
|
108
|
+
self.url_with_query_string,
|
109
|
+
:headers => self.headers.stringify_keys
|
110
|
+
)
|
111
|
+
|
112
|
+
when :post
|
113
|
+
Typhoeus::Request.post(
|
114
|
+
self.url_with_query_string,
|
115
|
+
:body => self.interpreted_body,
|
116
|
+
:headers => self.headers.stringify_keys
|
117
|
+
)
|
118
|
+
|
119
|
+
when :put
|
120
|
+
Typhoeus::Request.put(
|
121
|
+
self.url_with_query_string,
|
122
|
+
:body => self.interpreted_body,
|
123
|
+
:headers => self.headers.stringify_keys
|
124
|
+
)
|
125
|
+
|
126
|
+
when :delete
|
127
|
+
Typhoeus::Request.delete(
|
128
|
+
self.url_with_query_string,
|
129
|
+
:body => self.interpreted_body,
|
130
|
+
:headers => self.headers.stringify_keys
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
@response_obj = Response.new(response)
|
135
|
+
end
|
136
|
+
|
137
|
+
# If the request has been made, return the existing response
|
138
|
+
# If not, make the request and return the response
|
139
|
+
def response
|
140
|
+
@response_obj || self.make
|
141
|
+
end
|
142
|
+
|
143
|
+
def response_code_pretty
|
144
|
+
return unless @response.present?
|
145
|
+
@response.code.to_s
|
146
|
+
end
|
147
|
+
|
148
|
+
def response_headers_pretty
|
149
|
+
return unless @response.present?
|
150
|
+
# JSON.pretty_generate(@response.headers).gsub(/\n/, '<br/>').html_safe # <- This was for RestClient
|
151
|
+
@response.headers.gsub(/\n/, '<br/>').html_safe # <- This is for Typhoeus
|
152
|
+
end
|
153
|
+
|
154
|
+
# It's an ActiveModel thing..
|
155
|
+
def persisted?
|
156
|
+
false
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# To jog the memory: Resource > Endpoint > Operation > OperationParameter
|
2
|
+
|
3
|
+
class Resource
|
4
|
+
|
5
|
+
include ActiveModel::Validations
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
|
9
|
+
attr_accessor :name, :raw_data, :endpoints, :models
|
10
|
+
|
11
|
+
validates_presence_of :name, :raw_data, :endpoints, :models
|
12
|
+
|
13
|
+
def initialize(attributes = {})
|
14
|
+
attributes.each do |name, value|
|
15
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Generate Endpoint instances from JSON
|
19
|
+
if self.raw_data['endPoints']
|
20
|
+
self.endpoints = self.raw_data['endPoints'].map do |endpointData|
|
21
|
+
Endpoint.new(endpointData)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def operation_nickname_pairs
|
27
|
+
return unless self.endpoints.present?
|
28
|
+
pairs = {}
|
29
|
+
self.endpoints.map do |endpoint|
|
30
|
+
endpoint.operations.map do |operation|
|
31
|
+
nickname_parts = []
|
32
|
+
nickname_parts << operation.http_method
|
33
|
+
nickname_parts << endpoint.path.gsub(/\{\w+\}/, "").gsub("/", "_").nix(' ').nix('.').underscore
|
34
|
+
nickname = nickname_parts.
|
35
|
+
join("_").
|
36
|
+
gsub(/_+/, "_").
|
37
|
+
gsub("_#{self.name.underscore}", "").
|
38
|
+
gsub(/_$/, "")
|
39
|
+
pairs[nickname] = "#{operation.http_method.upcase} #{endpoint.path}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
pairs
|
43
|
+
end
|
44
|
+
|
45
|
+
# It's an ActiveModel thing..
|
46
|
+
def persisted?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class Response
|
2
|
+
include ActiveModel::Validations
|
3
|
+
include ActiveModel::Conversion
|
4
|
+
extend ActiveModel::Naming
|
5
|
+
|
6
|
+
attr_accessor :raw
|
7
|
+
|
8
|
+
validates_presence_of :raw
|
9
|
+
|
10
|
+
def initialize(raw)
|
11
|
+
self.raw = raw
|
12
|
+
end
|
13
|
+
|
14
|
+
def code
|
15
|
+
raw.code
|
16
|
+
end
|
17
|
+
|
18
|
+
# If body is JSON, parse it
|
19
|
+
# TODO: If body is XML, parse it
|
20
|
+
# Otherwise return raw string
|
21
|
+
def body
|
22
|
+
JSON.parse(raw.body)
|
23
|
+
rescue
|
24
|
+
raw.body
|
25
|
+
end
|
26
|
+
|
27
|
+
def headers
|
28
|
+
h = {}
|
29
|
+
raw.headers_hash.each {|k,v| h[k] = v }
|
30
|
+
h
|
31
|
+
end
|
32
|
+
|
33
|
+
# Extract the response format from the header hash
|
34
|
+
# e.g. {'Content-Type' => 'application/json'}
|
35
|
+
def format
|
36
|
+
headers['Content-Type'].split("/").last.to_sym
|
37
|
+
end
|
38
|
+
|
39
|
+
def json?
|
40
|
+
format == :json
|
41
|
+
end
|
42
|
+
|
43
|
+
def xml?
|
44
|
+
format == :xml
|
45
|
+
end
|
46
|
+
|
47
|
+
def pretty_body
|
48
|
+
return unless body.present?
|
49
|
+
case format
|
50
|
+
when :json
|
51
|
+
JSON.pretty_generate(body).gsub(/\n/, '<br/>').html_safe
|
52
|
+
when :xml
|
53
|
+
xsl = Nokogiri::XSLT(File.open(Rails.root.join("config", "pretty_print.xsl")))
|
54
|
+
xml = Nokogiri(body)
|
55
|
+
coder = HTMLEntities.new
|
56
|
+
coder.encode(xsl.apply_to(xml).to_s)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def pretty_headers
|
61
|
+
JSON.pretty_generate(headers).gsub(/\n/, '<br/>').html_safe
|
62
|
+
end
|
63
|
+
|
64
|
+
# It's an ActiveModel thing..
|
65
|
+
def persisted?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Endpoint do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
VCR.use_cassette('words', :record => :new_episodes) do
|
7
|
+
@response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
|
8
|
+
end
|
9
|
+
|
10
|
+
@endpoint = Endpoint.new(JSON.parse(@response.body)['endPoints'].first)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "initialization" do
|
14
|
+
|
15
|
+
it "successfully initializes" do
|
16
|
+
@endpoint.path.should == "/word.{format}/{word}"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets operations" do
|
20
|
+
@endpoint.operations.class.should == Array
|
21
|
+
@endpoint.operations.first.class.should == Operation
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OperationParameter do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
VCR.use_cassette('words', :record => :new_episodes) do
|
7
|
+
@response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
|
8
|
+
end
|
9
|
+
|
10
|
+
@operation_parameter = OperationParameter.new(JSON.parse(@response.body)['endPoints'].first['operations'].first['parameters'].first)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "initialization" do
|
14
|
+
|
15
|
+
it "successfully initializes" do
|
16
|
+
@operation_parameter.respond_to?(:name).should == true
|
17
|
+
@operation_parameter.respond_to?(:description).should == true
|
18
|
+
@operation_parameter.respond_to?(:required).should == true
|
19
|
+
@operation_parameter.respond_to?(:param_type).should == true
|
20
|
+
@operation_parameter.respond_to?(:default_value).should == true
|
21
|
+
@operation_parameter.respond_to?(:allowable_values).should == true
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Operation do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
VCR.use_cassette('words', :record => :new_episodes) do
|
7
|
+
@response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
|
8
|
+
end
|
9
|
+
|
10
|
+
@operation = Operation.new(JSON.parse(@response.body)['endPoints'].first['operations'].first)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "initialization" do
|
14
|
+
|
15
|
+
it "successfully initializes" do
|
16
|
+
@operation.summary.should =~ /returns the WordObject/i
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets parameters" do
|
20
|
+
@operation.parameters.class.should == Array
|
21
|
+
@operation.parameters.first.class.should == OperationParameter
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "instance methods" do
|
27
|
+
it "knows if its HTTP method is GET" do
|
28
|
+
@operation.http_method = "GET"
|
29
|
+
@operation.get?.should == true
|
30
|
+
@operation.http_method = "POST"
|
31
|
+
@operation.get?.should == false
|
32
|
+
@operation.http_method = "get"
|
33
|
+
@operation.get?.should == true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Request do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@default_http_method = :get
|
7
|
+
@default_path = "words/fancy"
|
8
|
+
@default_params = {
|
9
|
+
:params => {:foo => "1", :bar => "2"}
|
10
|
+
}
|
11
|
+
@request = Request.new(@default_http_method, @default_path, @default_params)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "initialization" do
|
15
|
+
it "sets default response format to json" do
|
16
|
+
@request.format.should == "json"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets get default host from Wordnik.configuration" do
|
20
|
+
@request.host.should == Wordnik.configuration.base_uri
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "attr_accessors" do
|
26
|
+
|
27
|
+
it "has working attributes" do
|
28
|
+
@request.host.should == Wordnik.configuration.base_uri
|
29
|
+
@request.path.should == "words/fancy"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allows attributes to be overwritten" do
|
33
|
+
@request.http_method.should == :get
|
34
|
+
@request.http_method = "post"
|
35
|
+
@request.http_method.should == 'post'
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "url" do
|
41
|
+
|
42
|
+
it "constructs a base URL" do
|
43
|
+
@request.url.should == "http://beta.wordnik.com/v4/words.json/fancy"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "constructs a query string" do
|
47
|
+
@request.query_string.should == "?bar=2&foo=1"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "constructs a full url" do
|
51
|
+
@request.url_with_query_string.should == "http://beta.wordnik.com/v4/words.json/fancy?bar=2&foo=1"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "accounts for excessive slashes" do
|
55
|
+
@request = Request.new(:get, "andBurn", @default_params.merge({
|
56
|
+
:host => "slash.com/"
|
57
|
+
}))
|
58
|
+
@request.url.should == "http://slash.com/andBurn.json"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "path" do
|
64
|
+
|
65
|
+
it "accounts for a total absence of format in the path string" do
|
66
|
+
@request = Request.new(:get, "/word/{word}/entries", @default_params.merge({
|
67
|
+
:format => "xml",
|
68
|
+
:params => {
|
69
|
+
:word => "cat"
|
70
|
+
}
|
71
|
+
}))
|
72
|
+
@request.url.should == "http://beta.wordnik.com/v4/word.xml/cat/entries"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "does string substitution on path params" do
|
76
|
+
@request = Request.new(:get, "/word.{format}/{word}/entries", @default_params.merge({
|
77
|
+
:format => "xml",
|
78
|
+
:params => {
|
79
|
+
:word => "cat"
|
80
|
+
}
|
81
|
+
}))
|
82
|
+
@request.url.should == "http://beta.wordnik.com/v4/word.xml/cat/entries"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "leaves path-bound params out of the query string" do
|
86
|
+
@request = Request.new(:get, "/word.{format}/{word}/entries", @default_params.merge({
|
87
|
+
:params => {
|
88
|
+
:word => "cat",
|
89
|
+
:limit => 20
|
90
|
+
}
|
91
|
+
}))
|
92
|
+
@request.query_string.should == "?limit=20"
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns a question-mark free (blank) query string if no query params are present" do
|
96
|
+
@request = Request.new(:get, "/word.{format}/{word}/entries", @default_params.merge({
|
97
|
+
:params => {
|
98
|
+
:word => "cat",
|
99
|
+
}
|
100
|
+
}))
|
101
|
+
@request.query_string.should == ""
|
102
|
+
end
|
103
|
+
|
104
|
+
it "removes blank params" do
|
105
|
+
@request = Request.new(:get, "words/fancy", @default_params.merge({
|
106
|
+
:params => {
|
107
|
+
:word => "dog",
|
108
|
+
:limit => "",
|
109
|
+
:foo => "criminy"
|
110
|
+
}
|
111
|
+
}))
|
112
|
+
@request.query_string.should == "?foo=criminy&word=dog"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "obfuscates the API key when needed" do
|
116
|
+
@request = Request.new(:get, "words/fancy", @default_params.merge({
|
117
|
+
:params => {
|
118
|
+
:word => "dog",
|
119
|
+
:api_key => "123456"
|
120
|
+
}
|
121
|
+
}))
|
122
|
+
@request.query_string_params.should == {:word => "dog", :api_key => "123456"}
|
123
|
+
@request.query_string_params(true).should == {:word => "dog", :api_key => "YOUR_API_KEY"}
|
124
|
+
|
125
|
+
@request.query_string.should == "?api_key=123456&word=dog"
|
126
|
+
@request.query_string(:obfuscated => true).should == "?api_key=YOUR_API_KEY&word=dog"
|
127
|
+
|
128
|
+
@request.url_with_query_string.should =~ /123456/
|
129
|
+
@request.url_with_query_string(:obfuscated => true).should =~ /YOUR\_API\_KEY/
|
130
|
+
end
|
131
|
+
|
132
|
+
it "URI encodes the path" do
|
133
|
+
@request = Request.new(:get, "word.{format}/{word}/definitions", @default_params.merge({
|
134
|
+
:params => {
|
135
|
+
:word => "bill gates"
|
136
|
+
}
|
137
|
+
}))
|
138
|
+
@request.url.should =~ /word.json\/bill\%20gates\/definitions/
|
139
|
+
end
|
140
|
+
|
141
|
+
it "converts numeric params to strings" do
|
142
|
+
@request = Request.new(@default_http_method, @default_path, @default_params.merge({
|
143
|
+
:params => {
|
144
|
+
:limit => 100
|
145
|
+
}
|
146
|
+
}))
|
147
|
+
|
148
|
+
@request.interpreted_path.should_not be_nil
|
149
|
+
@request.query_string.should =~ /\?limit=100/
|
150
|
+
@request.url_with_query_string.should =~ /\?limit=100/
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resource do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
VCR.use_cassette('words', :record => :new_episodes) do
|
7
|
+
@response = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
|
8
|
+
end
|
9
|
+
|
10
|
+
@default_params = {
|
11
|
+
:name => "word",
|
12
|
+
:raw_data => JSON.parse(@response.body)
|
13
|
+
}
|
14
|
+
|
15
|
+
@resource = Resource.new(@default_params)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "initialization" do
|
19
|
+
|
20
|
+
it "successfully initializes" do
|
21
|
+
@resource.name.should == "word"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "sets endpoints" do
|
25
|
+
@resource.endpoints.size.should == 10
|
26
|
+
@resource.endpoints.first.class.to_s.should == "Endpoint"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Response do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
|
7
|
+
VCR.use_cassette('default_response_request', :record => :new_episodes) do
|
8
|
+
@raw = Typhoeus::Request.get("http://api.wordnik.com/v4/word.json")
|
9
|
+
end
|
10
|
+
|
11
|
+
@response = Response.new(@raw)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "initialization" do
|
15
|
+
it "sets body" do
|
16
|
+
@response.body.class.should == Hash
|
17
|
+
@response.body.has_key?('endPoints').should == true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sets code" do
|
21
|
+
@response.code.should == 200
|
22
|
+
end
|
23
|
+
|
24
|
+
it "converts header string into a hash" do
|
25
|
+
@response.headers.class.should == Hash
|
26
|
+
@response.headers['Wordnik-Api-Version'].to_s.should =~ /4\.0/
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "format" do
|
32
|
+
|
33
|
+
it "recognizes json" do
|
34
|
+
@response.format.should == :json
|
35
|
+
@response.json?.should == true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "recognizes xml" do
|
39
|
+
VCR.use_cassette('xml_response_request', :record => :new_episodes) do
|
40
|
+
@raw = Typhoeus::Request.get("http://api.wordnik.com/v4/word.xml/help")
|
41
|
+
end
|
42
|
+
@response = Response.new(@raw)
|
43
|
+
@response.format.should == :xml
|
44
|
+
@response.xml?.should == true
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'wordnik'
|
4
|
+
require 'vcr'
|
5
|
+
require 'typhoeus'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
# some (optional) config here
|
10
|
+
end
|
11
|
+
|
12
|
+
VCR.config do |config|
|
13
|
+
config.cassette_library_dir = 'spec/vcr'
|
14
|
+
config.stub_with :webmock # or :fakeweb
|
15
|
+
end
|
16
|
+
|
17
|
+
Wordnik.configure do |config|
|
18
|
+
config.api_key = "12345"
|
19
|
+
end
|
data/wordnik.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "wordnik/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "wordnik"
|
7
|
+
s.version = Wordnik::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Zeke Sikelianos", "John McGrath"]
|
10
|
+
s.email = ["zeke@wordnik.com", "john@wordnik.com"]
|
11
|
+
s.homepage = "http://developer.wordnik.com"
|
12
|
+
s.summary = %q{A ruby wrapper for the Wordnik API}
|
13
|
+
s.description = %q{This gem provides a simple interface to the entire Wordnik API. Its methods are defined by the documentation that comes from the API itself, so it's guaranteed to be up to date.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "wordnik"
|
16
|
+
|
17
|
+
s.add_dependency 'typhoeus', '0.2.1'
|
18
|
+
s.add_dependency 'htmlentities', '4.2.4'
|
19
|
+
s.add_dependency 'addressable', '2.2.4'
|
20
|
+
s.add_dependency 'nokogiri', '1.4.4'
|
21
|
+
s.add_dependency 'activemodel', '3.0.3'
|
22
|
+
s.add_dependency 'json', '1.4.6'
|
23
|
+
|
24
|
+
s.add_development_dependency 'rspec', '2.4.0'
|
25
|
+
s.add_development_dependency 'vcr', '1.5.1'
|
26
|
+
s.add_development_dependency 'webmock', '1.6.2'
|
27
|
+
|
28
|
+
s.files = `git ls-files`.split("\n")
|
29
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
30
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
31
|
+
s.require_paths = ["lib"]
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wordnik
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Zeke Sikelianos
|
13
|
+
- John McGrath
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-16 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: typhoeus
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - "="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
- 2
|
32
|
+
- 1
|
33
|
+
version: 0.2.1
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: htmlentities
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - "="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
segments:
|
45
|
+
- 4
|
46
|
+
- 2
|
47
|
+
- 4
|
48
|
+
version: 4.2.4
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: addressable
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - "="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 2
|
61
|
+
- 2
|
62
|
+
- 4
|
63
|
+
version: 2.2.4
|
64
|
+
type: :runtime
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: nokogiri
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - "="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 1
|
76
|
+
- 4
|
77
|
+
- 4
|
78
|
+
version: 1.4.4
|
79
|
+
type: :runtime
|
80
|
+
version_requirements: *id004
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: activemodel
|
83
|
+
prerelease: false
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - "="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
segments:
|
90
|
+
- 3
|
91
|
+
- 0
|
92
|
+
- 3
|
93
|
+
version: 3.0.3
|
94
|
+
type: :runtime
|
95
|
+
version_requirements: *id005
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: json
|
98
|
+
prerelease: false
|
99
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - "="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
segments:
|
105
|
+
- 1
|
106
|
+
- 4
|
107
|
+
- 6
|
108
|
+
version: 1.4.6
|
109
|
+
type: :runtime
|
110
|
+
version_requirements: *id006
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
prerelease: false
|
114
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - "="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
segments:
|
120
|
+
- 2
|
121
|
+
- 4
|
122
|
+
- 0
|
123
|
+
version: 2.4.0
|
124
|
+
type: :development
|
125
|
+
version_requirements: *id007
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: vcr
|
128
|
+
prerelease: false
|
129
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - "="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
segments:
|
135
|
+
- 1
|
136
|
+
- 5
|
137
|
+
- 1
|
138
|
+
version: 1.5.1
|
139
|
+
type: :development
|
140
|
+
version_requirements: *id008
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: webmock
|
143
|
+
prerelease: false
|
144
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - "="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
segments:
|
150
|
+
- 1
|
151
|
+
- 6
|
152
|
+
- 2
|
153
|
+
version: 1.6.2
|
154
|
+
type: :development
|
155
|
+
version_requirements: *id009
|
156
|
+
description: This gem provides a simple interface to the entire Wordnik API. Its methods are defined by the documentation that comes from the API itself, so it's guaranteed to be up to date.
|
157
|
+
email:
|
158
|
+
- zeke@wordnik.com
|
159
|
+
- john@wordnik.com
|
160
|
+
executables: []
|
161
|
+
|
162
|
+
extensions: []
|
163
|
+
|
164
|
+
extra_rdoc_files: []
|
165
|
+
|
166
|
+
files:
|
167
|
+
- .gitignore
|
168
|
+
- Gemfile
|
169
|
+
- Gemfile.lock
|
170
|
+
- README.md
|
171
|
+
- Rakefile
|
172
|
+
- lib/wordnik.rb
|
173
|
+
- lib/wordnik/configuration.rb
|
174
|
+
- lib/wordnik/endpoint.rb
|
175
|
+
- lib/wordnik/operation.rb
|
176
|
+
- lib/wordnik/operation_parameter.rb
|
177
|
+
- lib/wordnik/request.rb
|
178
|
+
- lib/wordnik/resource.rb
|
179
|
+
- lib/wordnik/response.rb
|
180
|
+
- lib/wordnik/version.rb
|
181
|
+
- spec/endpoint_spec.rb
|
182
|
+
- spec/operation_parameter_spec.rb
|
183
|
+
- spec/operation_spec.rb
|
184
|
+
- spec/request_spec.rb
|
185
|
+
- spec/resource_spec.rb
|
186
|
+
- spec/response_spec.rb
|
187
|
+
- spec/spec.opts
|
188
|
+
- spec/spec_helper.rb
|
189
|
+
- spec/wordnik_spec.rb
|
190
|
+
- wordnik.gemspec
|
191
|
+
has_rdoc: true
|
192
|
+
homepage: http://developer.wordnik.com
|
193
|
+
licenses: []
|
194
|
+
|
195
|
+
post_install_message:
|
196
|
+
rdoc_options: []
|
197
|
+
|
198
|
+
require_paths:
|
199
|
+
- lib
|
200
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
segments:
|
206
|
+
- 0
|
207
|
+
version: "0"
|
208
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
209
|
+
none: false
|
210
|
+
requirements:
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
segments:
|
214
|
+
- 0
|
215
|
+
version: "0"
|
216
|
+
requirements: []
|
217
|
+
|
218
|
+
rubyforge_project: wordnik
|
219
|
+
rubygems_version: 1.3.7
|
220
|
+
signing_key:
|
221
|
+
specification_version: 3
|
222
|
+
summary: A ruby wrapper for the Wordnik API
|
223
|
+
test_files:
|
224
|
+
- spec/endpoint_spec.rb
|
225
|
+
- spec/operation_parameter_spec.rb
|
226
|
+
- spec/operation_spec.rb
|
227
|
+
- spec/request_spec.rb
|
228
|
+
- spec/resource_spec.rb
|
229
|
+
- spec/response_spec.rb
|
230
|
+
- spec/spec.opts
|
231
|
+
- spec/spec_helper.rb
|
232
|
+
- spec/wordnik_spec.rb
|