wordnik 0.0.1 → 0.0.2
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/lib/wordnik/endpoint.rb +23 -22
- data/lib/wordnik/operation.rb +33 -30
- data/lib/wordnik/operation_parameter.rb +29 -26
- data/lib/wordnik/request.rb +133 -129
- data/lib/wordnik/resource.rb +39 -36
- data/lib/wordnik/response.rb +58 -54
- data/lib/wordnik/version.rb +1 -1
- metadata +2 -2
data/lib/wordnik/endpoint.rb
CHANGED
@@ -1,32 +1,33 @@
|
|
1
|
-
|
2
|
-
require 'active_model'
|
1
|
+
module Wordnik
|
3
2
|
|
4
|
-
class Endpoint
|
3
|
+
class Endpoint
|
4
|
+
require 'active_model'
|
5
|
+
include ActiveModel::Validations
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
5
8
|
|
6
|
-
|
7
|
-
include ActiveModel::Conversion
|
8
|
-
extend ActiveModel::Naming
|
9
|
+
attr_accessor :path, :description, :operations
|
9
10
|
|
10
|
-
|
11
|
+
validates_presence_of :path, :description, :operations
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
send("#{name.to_s.underscore.to_sym}=", value)
|
17
|
-
end
|
13
|
+
def initialize(attributes = {})
|
14
|
+
attributes.each do |name, value|
|
15
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
# Generate Operations instances from JSON
|
19
|
+
if self.operations
|
20
|
+
self.operations = self.operations.map do |operationData|
|
21
|
+
Operation.new(operationData)
|
22
|
+
end
|
23
23
|
end
|
24
24
|
end
|
25
|
-
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
# It's an ActiveModel thing..
|
27
|
+
def persisted?
|
28
|
+
false
|
29
|
+
end
|
31
30
|
|
31
|
+
end
|
32
|
+
|
32
33
|
end
|
data/lib/wordnik/operation.rb
CHANGED
@@ -1,42 +1,45 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class Operation
|
4
|
-
include ActiveModel::Validations
|
5
|
-
include ActiveModel::Conversion
|
6
|
-
extend ActiveModel::Naming
|
1
|
+
module Wordnik
|
7
2
|
|
8
|
-
|
3
|
+
class Operation
|
4
|
+
require 'active_model'
|
5
|
+
include ActiveModel::Validations
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
9
8
|
|
10
|
-
|
9
|
+
attr_accessor :http_method, :summary, :notes, :parameters, :response, :open
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
validates_presence_of :http_method, :summary, :notes, :parameters, :response, :open
|
12
|
+
|
13
|
+
def initialize(attributes = {})
|
14
|
+
attributes.each do |name, value|
|
15
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
+
self.http_method = self.http_method.to_s.downcase
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# Generate OperationParameter instances from JSON
|
21
|
+
if self.parameters
|
22
|
+
self.parameters = self.parameters.map do |parameterData|
|
23
|
+
OperationParameter.new(parameterData)
|
24
|
+
end
|
23
25
|
end
|
24
|
-
end
|
25
26
|
|
26
|
-
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def get?
|
30
|
+
self.http_method.downcase == "get"
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
# Can this operation be run in the sandbox?
|
34
|
+
def sandboxable?
|
35
|
+
self.get?
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
# It's an ActiveModel thing..
|
39
|
+
def persisted?
|
40
|
+
false
|
41
|
+
end
|
41
42
|
|
43
|
+
end
|
44
|
+
|
42
45
|
end
|
@@ -1,36 +1,39 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class OperationParameter
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Wordnik
|
2
|
+
|
3
|
+
class OperationParameter
|
4
|
+
require 'active_model'
|
5
|
+
include ActiveModel::Validations
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
7
8
|
|
8
|
-
|
9
|
+
attr_accessor :name, :description, :required, :param_type, :default_value, :allowable_values
|
9
10
|
|
10
|
-
|
11
|
+
validates_presence_of :name, :description, :required, :param_type, :default_value, :allowable_values
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def initialize(attributes = {})
|
14
|
+
attributes.each do |name, value|
|
15
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
16
|
+
end
|
15
17
|
end
|
16
|
-
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def human_name
|
20
|
+
return "request body" if self.param_type == 'body'
|
21
|
+
self.name
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
def has_allowable_array?
|
25
|
+
self.allowable_values.present? && self.allowable_values.include?(",")
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def required?
|
29
|
+
self.required
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
# It's an ActiveModel thing..
|
33
|
+
def persisted?
|
34
|
+
false
|
35
|
+
end
|
35
36
|
|
37
|
+
end
|
38
|
+
|
36
39
|
end
|
data/lib/wordnik/request.rb
CHANGED
@@ -1,159 +1,163 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
module Wordnik
|
2
|
+
|
3
|
+
class Request
|
4
|
+
require 'uri'
|
5
|
+
require 'addressable/uri'
|
6
|
+
require 'typhoeus'
|
7
|
+
require 'active_model'
|
8
|
+
include ActiveModel::Validations
|
9
|
+
include ActiveModel::Conversion
|
10
|
+
extend ActiveModel::Naming
|
8
11
|
|
9
|
-
|
12
|
+
attr_accessor :host, :port, :path, :format, :params, :body, :http_method, :headers
|
10
13
|
|
11
|
-
|
14
|
+
validates_presence_of :host, :path, :format, :http_method
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
def initialize(http_method, path, attributes={})
|
17
|
+
attributes[:format] ||= "json"
|
18
|
+
attributes[:host] ||= Wordnik.configuration.base_uri
|
19
|
+
attributes[:params] ||= {}
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
# Set default headers, but allow them to be overridden
|
22
|
+
default_headers = {
|
23
|
+
'Content-Type' => "application/#{attributes[:format].downcase}",
|
24
|
+
}
|
25
|
+
attributes[:headers] = default_headers.merge(attributes[:headers] || {})
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
self.http_method = http_method.to_sym
|
28
|
+
self.path = path
|
29
|
+
attributes.each do |name, value|
|
30
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
31
|
+
end
|
28
32
|
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
33
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
34
|
+
# Construct a base URL
|
35
|
+
def url
|
36
|
+
u = Addressable::URI.new
|
37
|
+
u.host = self.host.sub(/\/$/, '')
|
38
|
+
u.port = self.port if self.port.present?
|
39
|
+
u.path = self.interpreted_path
|
40
|
+
u.scheme = "http" # For some reason this must be set _after_ host, otherwise Addressable gets upset
|
41
|
+
u.to_s
|
47
42
|
end
|
43
|
+
|
44
|
+
# Iterate over the params hash, injecting any path values into the path string
|
45
|
+
# e.g. /word.{format}/{word}/entries => /word.json/cat/entries
|
46
|
+
def interpreted_path
|
47
|
+
p = self.path
|
48
|
+
self.params.each_pair do |key, value|
|
49
|
+
p = p.gsub("{#{key}}", value.to_s)
|
50
|
+
end
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
# Stick a .{format} placeholder into the path if there isn't
|
53
|
+
# one already or an actual format like json or xml
|
54
|
+
# e.g. /words/blah => /words.{format}/blah
|
55
|
+
unless ['.json', '.xml', '{format}'].any? {|s| p.downcase.include? s }
|
56
|
+
p = p.sub(/^(\/?\w+)/, "\\1.#{format}")
|
57
|
+
end
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
p = p.sub("{format}", self.format)
|
60
|
+
URI.encode(p)
|
61
|
+
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
def interpreted_body
|
64
|
+
return unless self.body.present?
|
65
|
+
return self.body.to_json if self.body.is_a?(Hash)
|
66
|
+
self.body
|
67
|
+
end
|
65
68
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
# Iterate over all params,
|
70
|
+
# .. removing the ones that are part of the path itself.
|
71
|
+
# .. stringifying values so Addressable doesn't blow up.
|
72
|
+
# .. obfuscating the API key if needed.
|
73
|
+
def query_string_params(obfuscated=false)
|
74
|
+
qsp = {}
|
75
|
+
self.params.each_pair do |key, value|
|
76
|
+
next if self.path.include? "{#{key}}"
|
77
|
+
next if value.blank?
|
78
|
+
value = "YOUR_API_KEY" if key.to_sym == :api_key && obfuscated
|
79
|
+
qsp[key] = value.to_s
|
80
|
+
end
|
81
|
+
qsp
|
77
82
|
end
|
78
|
-
qsp
|
79
|
-
end
|
80
83
|
|
81
|
-
|
82
|
-
|
84
|
+
# Construct a query string from the query-string-type params
|
85
|
+
def query_string(options={})
|
83
86
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
+
# We don't want to end up with '?' as our query string
|
88
|
+
# if there aren't really any params
|
89
|
+
return "" if query_string_params.blank?
|
87
90
|
|
88
|
-
|
89
|
-
|
91
|
+
default_options = {:obfuscated => false}
|
92
|
+
options = default_options.merge(options)
|
90
93
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
94
|
+
qs = Addressable::URI.new
|
95
|
+
qs.query_values = self.query_string_params(options[:obfuscated])
|
96
|
+
qs.to_s
|
97
|
+
end
|
95
98
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
99
|
+
# Returns full request URL with query string included
|
100
|
+
def url_with_query_string(options={})
|
101
|
+
default_options = {:obfuscated => false}
|
102
|
+
options = default_options.merge(options)
|
100
103
|
|
101
|
-
|
102
|
-
|
104
|
+
[url, query_string(options)].join('')
|
105
|
+
end
|
103
106
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
107
|
+
def make
|
108
|
+
response = case self.http_method.to_sym
|
109
|
+
when :get
|
110
|
+
Typhoeus::Request.get(
|
111
|
+
self.url_with_query_string,
|
112
|
+
:headers => self.headers.stringify_keys
|
113
|
+
)
|
111
114
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
115
|
+
when :post
|
116
|
+
Typhoeus::Request.post(
|
117
|
+
self.url_with_query_string,
|
118
|
+
:body => self.interpreted_body,
|
119
|
+
:headers => self.headers.stringify_keys
|
120
|
+
)
|
118
121
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
122
|
+
when :put
|
123
|
+
Typhoeus::Request.put(
|
124
|
+
self.url_with_query_string,
|
125
|
+
:body => self.interpreted_body,
|
126
|
+
:headers => self.headers.stringify_keys
|
127
|
+
)
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
129
|
+
when :delete
|
130
|
+
Typhoeus::Request.delete(
|
131
|
+
self.url_with_query_string,
|
132
|
+
:body => self.interpreted_body,
|
133
|
+
:headers => self.headers.stringify_keys
|
134
|
+
)
|
135
|
+
end
|
133
136
|
|
134
|
-
|
135
|
-
|
137
|
+
@response_obj = Response.new(response)
|
138
|
+
end
|
136
139
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
140
|
+
# If the request has been made, return the existing response
|
141
|
+
# If not, make the request and return the response
|
142
|
+
def response
|
143
|
+
@response_obj || self.make
|
144
|
+
end
|
142
145
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
146
|
+
def response_code_pretty
|
147
|
+
return unless @response.present?
|
148
|
+
@response.code.to_s
|
149
|
+
end
|
147
150
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
151
|
+
def response_headers_pretty
|
152
|
+
return unless @response.present?
|
153
|
+
# JSON.pretty_generate(@response.headers).gsub(/\n/, '<br/>').html_safe # <- This was for RestClient
|
154
|
+
@response.headers.gsub(/\n/, '<br/>').html_safe # <- This is for Typhoeus
|
155
|
+
end
|
153
156
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
157
|
+
# It's an ActiveModel thing..
|
158
|
+
def persisted?
|
159
|
+
false
|
160
|
+
end
|
158
161
|
|
162
|
+
end
|
159
163
|
end
|
data/lib/wordnik/resource.rb
CHANGED
@@ -1,50 +1,53 @@
|
|
1
1
|
# To jog the memory: Resource > Endpoint > Operation > OperationParameter
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module Wordnik
|
4
|
+
class Resource
|
5
|
+
require 'active_model'
|
6
|
+
include ActiveModel::Validations
|
7
|
+
include ActiveModel::Conversion
|
8
|
+
extend ActiveModel::Naming
|
8
9
|
|
9
|
-
|
10
|
+
attr_accessor :name, :raw_data, :endpoints, :models
|
10
11
|
|
11
|
-
|
12
|
+
validates_presence_of :name, :raw_data, :endpoints, :models
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def initialize(attributes = {})
|
15
|
+
attributes.each do |name, value|
|
16
|
+
send("#{name.to_s.underscore.to_sym}=", value)
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
# Generate Endpoint instances from JSON
|
20
|
+
if self.raw_data['endPoints']
|
21
|
+
self.endpoints = self.raw_data['endPoints'].map do |endpointData|
|
22
|
+
Endpoint.new(endpointData)
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
|
-
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
27
|
+
def operation_nickname_pairs
|
28
|
+
return unless self.endpoints.present?
|
29
|
+
pairs = {}
|
30
|
+
self.endpoints.map do |endpoint|
|
31
|
+
endpoint.operations.map do |operation|
|
32
|
+
nickname_parts = []
|
33
|
+
nickname_parts << operation.http_method
|
34
|
+
nickname_parts << endpoint.path.gsub(/\{\w+\}/, "").gsub("/", "_").nix(' ').nix('.').underscore
|
35
|
+
nickname = nickname_parts.
|
36
|
+
join("_").
|
37
|
+
gsub(/_+/, "_").
|
38
|
+
gsub("_#{self.name.underscore}", "").
|
39
|
+
gsub(/_$/, "")
|
40
|
+
pairs[nickname] = "#{operation.http_method.upcase} #{endpoint.path}"
|
41
|
+
end
|
40
42
|
end
|
43
|
+
pairs
|
41
44
|
end
|
42
|
-
pairs
|
43
|
-
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
# It's an ActiveModel thing..
|
47
|
+
def persisted?
|
48
|
+
false
|
49
|
+
end
|
49
50
|
|
51
|
+
end
|
52
|
+
|
50
53
|
end
|
data/lib/wordnik/response.rb
CHANGED
@@ -1,69 +1,73 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Wordnik
|
2
|
+
|
3
|
+
class Response
|
4
|
+
require 'active_model'
|
5
|
+
include ActiveModel::Validations
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
5
8
|
|
6
|
-
|
9
|
+
attr_accessor :raw
|
7
10
|
|
8
|
-
|
11
|
+
validates_presence_of :raw
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
def initialize(raw)
|
14
|
+
self.raw = raw
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
def code
|
18
|
+
raw.code
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
# If body is JSON, parse it
|
22
|
+
# TODO: If body is XML, parse it
|
23
|
+
# Otherwise return raw string
|
24
|
+
def body
|
25
|
+
JSON.parse(raw.body)
|
26
|
+
rescue
|
27
|
+
raw.body
|
28
|
+
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
def headers
|
31
|
+
h = {}
|
32
|
+
raw.headers_hash.each {|k,v| h[k] = v }
|
33
|
+
h
|
34
|
+
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
# Extract the response format from the header hash
|
37
|
+
# e.g. {'Content-Type' => 'application/json'}
|
38
|
+
def format
|
39
|
+
headers['Content-Type'].split("/").last.to_sym
|
40
|
+
end
|
38
41
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
def json?
|
43
|
+
format == :json
|
44
|
+
end
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
def xml?
|
47
|
+
format == :xml
|
48
|
+
end
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
def pretty_body
|
51
|
+
return unless body.present?
|
52
|
+
case format
|
53
|
+
when :json
|
54
|
+
JSON.pretty_generate(body).gsub(/\n/, '<br/>').html_safe
|
55
|
+
when :xml
|
56
|
+
xsl = Nokogiri::XSLT(File.open(Rails.root.join("config", "pretty_print.xsl")))
|
57
|
+
xml = Nokogiri(body)
|
58
|
+
coder = HTMLEntities.new
|
59
|
+
coder.encode(xsl.apply_to(xml).to_s)
|
60
|
+
end
|
57
61
|
end
|
58
|
-
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
def pretty_headers
|
64
|
+
JSON.pretty_generate(headers).gsub(/\n/, '<br/>').html_safe
|
65
|
+
end
|
63
66
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
# It's an ActiveModel thing..
|
68
|
+
def persisted?
|
69
|
+
false
|
70
|
+
end
|
68
71
|
|
72
|
+
end
|
69
73
|
end
|
data/lib/wordnik/version.rb
CHANGED