tamber 0.1.6 → 0.1.7
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.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.travis.yml +11 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +223 -0
- data/README.rdoc +196 -0
- data/Rakefile +7 -0
- data/VERSION +1 -0
- data/lib/security/ca-bundle.crt +3893 -0
- data/lib/tamber/api_operations/create.rb +10 -0
- data/lib/tamber/api_operations/remove.rb +10 -0
- data/lib/tamber/api_operations/request.rb +21 -0
- data/lib/tamber/api_operations/retrieve.rb +10 -0
- data/lib/tamber/api_operations/update.rb +10 -0
- data/lib/tamber/api_resource.rb +21 -0
- data/lib/tamber/behavior.rb +6 -0
- data/lib/tamber/discover.rb +81 -0
- data/lib/tamber/event.rb +24 -0
- data/lib/tamber/item.rb +37 -0
- data/lib/tamber/tamber_error.rb +10 -0
- data/lib/tamber/tamber_object.rb +35 -0
- data/lib/tamber/user.rb +18 -0
- data/lib/tamber/util.rb +89 -0
- data/lib/tamber/version.rb +3 -0
- data/lib/tamber.rb +202 -0
- data/tamber.gemspec +35 -0
- data/test/discover_test.rb +56 -10
- data/test/item_test.rb +13 -2
- metadata +28 -2
@@ -0,0 +1,21 @@
|
|
1
|
+
module Tamber
|
2
|
+
module APIOperations
|
3
|
+
module Request
|
4
|
+
module ClassMethods
|
5
|
+
def request(method, url, params={})
|
6
|
+
response = Tamber.request(method, url, params)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.extend(ClassMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def request(method, url, params={})
|
17
|
+
self.class.request(method, url, params)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Tamber
|
2
|
+
class APIResource < TamberObject
|
3
|
+
include Tamber::APIOperations::Request
|
4
|
+
|
5
|
+
def self.class_name
|
6
|
+
self.name.split('::')[-1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.url
|
10
|
+
if self == APIResource
|
11
|
+
raise TamberError.new('APIResource is an abstract class. You should perform actions on its subclasses (Event, Discover, etc.)')
|
12
|
+
end
|
13
|
+
"/#{CGI.escape(class_name.downcase)}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def url
|
17
|
+
"#{self.class.url}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Tamber
|
2
|
+
class Discover < APIResource
|
3
|
+
|
4
|
+
def self.next(params={})
|
5
|
+
response = request(:get, self.next_url, params)
|
6
|
+
Util.convert_to_tamber_object(response)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.recommended(params={})
|
10
|
+
response = request(:get, self.recommended_url, params)
|
11
|
+
Util.convert_to_tamber_object(response)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.similar(params={})
|
15
|
+
response = request(:get, self.similar_url, params)
|
16
|
+
Util.convert_to_tamber_object(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.recommendedSimilar(params={})
|
20
|
+
response = request(:get, self.recommendedSimilar_url, params)
|
21
|
+
Util.convert_to_tamber_object(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.popular(params={})
|
25
|
+
response = request(:get, self.popular_url, params)
|
26
|
+
Util.convert_to_tamber_object(response)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.hot(params={})
|
30
|
+
response = request(:get, self.hot_url, params)
|
31
|
+
Util.convert_to_tamber_object(response)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.uac(params={})
|
35
|
+
response = request(:get, self.uac_url, params)
|
36
|
+
Util.convert_to_tamber_object(response)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.new(params={})
|
40
|
+
response = request(:get, self.new_url, params)
|
41
|
+
Util.convert_to_tamber_object(response)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.recommended_url
|
45
|
+
url + '/recommended'
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.similar_url
|
49
|
+
url + '/similar'
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.recommendedSimilar_url
|
53
|
+
url + '/recommended_similar'
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.next_url
|
57
|
+
url + '/next'
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.popular_url
|
61
|
+
url + '/popular'
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.hot_url
|
65
|
+
url + '/hot'
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.uac_url
|
69
|
+
url + '/uac'
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.new_url
|
73
|
+
url + '/new'
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
# Discover requests return an array of 'discovery' objects
|
79
|
+
class Discovery < TamberObject
|
80
|
+
end
|
81
|
+
end
|
data/lib/tamber/event.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Tamber
|
2
|
+
class Event < APIResource
|
3
|
+
|
4
|
+
extend Tamber::APIOperations::Retrieve
|
5
|
+
|
6
|
+
def self.track_url
|
7
|
+
url + '/track'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.batch_url
|
11
|
+
url + '/batch'
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.track(params={})
|
15
|
+
response = request(:post, self.track_url, params)
|
16
|
+
Util.convert_to_tamber_object(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.batch(params={})
|
20
|
+
response = request(:post, self.batch_url, params)
|
21
|
+
Util.convert_to_tamber_object(response)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/tamber/item.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Tamber
|
2
|
+
class Item < APIResource
|
3
|
+
extend Tamber::APIOperations::Create
|
4
|
+
extend Tamber::APIOperations::Update
|
5
|
+
extend Tamber::APIOperations::Retrieve
|
6
|
+
|
7
|
+
# hide an item from all Discover results
|
8
|
+
def self.hide(params={})
|
9
|
+
response = request(:post, self.hide_url, params)
|
10
|
+
Util.convert_to_tamber_object(response)
|
11
|
+
end
|
12
|
+
|
13
|
+
# un-hide an item from all Discover results
|
14
|
+
def self.unhide(params={})
|
15
|
+
response = request(:post, self.unhide_url, params)
|
16
|
+
Util.convert_to_tamber_object(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
# permenantly delete an item and all associated events
|
20
|
+
def self.delete(params={})
|
21
|
+
response = request(:post, self.delete_url, params)
|
22
|
+
Util.convert_to_tamber_object(response)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.hide_url
|
26
|
+
url + '/hide'
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.unhide_url
|
30
|
+
url + '/unhide'
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.delete_url
|
34
|
+
url + '/delete'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Tamber
|
2
|
+
class TamberObject
|
3
|
+
|
4
|
+
def initialize(values={})
|
5
|
+
values.each do |k,v|
|
6
|
+
val = self.class.curvert(v)
|
7
|
+
self.instance_variable_set("@#{k}", val)
|
8
|
+
self.singleton_class.send(:attr_accessor, k)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.construct_from(values)
|
13
|
+
values = Tamber::Util.symbolize_names(values)
|
14
|
+
self.new(values)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.curvert(values={})
|
18
|
+
case values
|
19
|
+
when Hash
|
20
|
+
if values.has_key?(:object)
|
21
|
+
Tamber::Util.object_classes.fetch(values[:object],TamberObject).new(values)
|
22
|
+
else
|
23
|
+
values.each do |k,v|
|
24
|
+
values[k] = curvert(v)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
when Array
|
28
|
+
values.map { |i| curvert(i) }
|
29
|
+
else
|
30
|
+
values
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/tamber/user.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Tamber
|
2
|
+
class User < APIResource
|
3
|
+
extend Tamber::APIOperations::Create
|
4
|
+
extend Tamber::APIOperations::Update
|
5
|
+
extend Tamber::APIOperations::Retrieve
|
6
|
+
|
7
|
+
def self.search(params={})
|
8
|
+
response = request(:post, url + '/search', params)
|
9
|
+
Util.convert_to_tamber_object(response)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.merge(params={})
|
13
|
+
response = request(:post, url + '/merge', params)
|
14
|
+
Util.convert_to_tamber_object(response)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/tamber/util.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Tamber
|
5
|
+
module Util
|
6
|
+
|
7
|
+
def self.encode_parameters(params)
|
8
|
+
Util.flatten_params(params).
|
9
|
+
map { |k,v| "#{url_encode(k)}=#{url_encode(v)}" }.join('&')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.url_encode(key)
|
13
|
+
CGI.escape(key.to_s).
|
14
|
+
gsub('%5B', '[').gsub('%5D', ']')
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.flatten_params(params, parent_key=nil)
|
18
|
+
result = []
|
19
|
+
|
20
|
+
params.sort_by { |(k, v)| k.to_s }.each do |key, value|
|
21
|
+
calculated_key = parent_key ? "#{parent_key}[#{key}]" : "#{key}"
|
22
|
+
if value.is_a?(Hash) || value.is_a?(Array) || value.is_a?(APIResource)
|
23
|
+
result << [calculated_key, value.to_json]
|
24
|
+
else
|
25
|
+
result << [calculated_key, value]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.object_classes
|
33
|
+
@object_classes ||= {
|
34
|
+
# Core
|
35
|
+
'event' => Event,
|
36
|
+
'discovery' => Discovery,
|
37
|
+
|
38
|
+
# Expanded
|
39
|
+
'user' => User,
|
40
|
+
'item' => Item,
|
41
|
+
'behavior' => Behavior,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.convert_full(resp)
|
46
|
+
case resp
|
47
|
+
when Hash
|
48
|
+
object_classes.fetch(resp[:object],TamberObject).construct_from(resp)
|
49
|
+
when Array
|
50
|
+
resp.map { |i| convert_full(i) }
|
51
|
+
else
|
52
|
+
resp
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.convert_to_tamber_object(resp)
|
57
|
+
case resp
|
58
|
+
when Hash
|
59
|
+
object_classes.fetch(resp[:object],TamberObject).construct_from(resp)
|
60
|
+
when Array
|
61
|
+
if resp.size == 1
|
62
|
+
resp = resp[0]
|
63
|
+
self.convert_full(resp)
|
64
|
+
else
|
65
|
+
resp.map { |i| convert_full(i) }
|
66
|
+
end
|
67
|
+
else
|
68
|
+
resp
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.symbolize_names(object)
|
73
|
+
case object
|
74
|
+
when Hash
|
75
|
+
new_hash = {}
|
76
|
+
object.each do |key, value|
|
77
|
+
key = (key.to_sym rescue key) || key
|
78
|
+
new_hash[key] = symbolize_names(value)
|
79
|
+
end
|
80
|
+
new_hash
|
81
|
+
when Array
|
82
|
+
object.map { |value| symbolize_names(value) }
|
83
|
+
else
|
84
|
+
object
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
data/lib/tamber.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
# Tamber Ruby bindings
|
2
|
+
# API spec at https://tamber.com/docs/api
|
3
|
+
require 'cgi'
|
4
|
+
require 'openssl'
|
5
|
+
require 'rbconfig'
|
6
|
+
require 'set'
|
7
|
+
require 'socket'
|
8
|
+
require 'base64'
|
9
|
+
|
10
|
+
require 'rest-client'
|
11
|
+
require 'json'
|
12
|
+
|
13
|
+
require 'tamber/version'
|
14
|
+
|
15
|
+
require 'tamber/api_operations/create'
|
16
|
+
require 'tamber/api_operations/update'
|
17
|
+
require 'tamber/api_operations/remove'
|
18
|
+
require 'tamber/api_operations/retrieve'
|
19
|
+
require 'tamber/api_operations/request'
|
20
|
+
|
21
|
+
require 'tamber/tamber_object'
|
22
|
+
require 'tamber/util'
|
23
|
+
require 'tamber/api_resource'
|
24
|
+
require 'tamber/discover'
|
25
|
+
require 'tamber/event'
|
26
|
+
require 'tamber/user'
|
27
|
+
require 'tamber/item'
|
28
|
+
require 'tamber/behavior'
|
29
|
+
|
30
|
+
|
31
|
+
require 'tamber/tamber_error'
|
32
|
+
|
33
|
+
|
34
|
+
module Tamber
|
35
|
+
DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/security/ca-bundle.crt'
|
36
|
+
|
37
|
+
@ca_bundle_path = DEFAULT_CA_BUNDLE_PATH
|
38
|
+
@verify_ssl_certs = true
|
39
|
+
|
40
|
+
@api_url = 'https://api.tamber.com/v1'
|
41
|
+
@open_timeout = 30
|
42
|
+
@read_timeout = 80
|
43
|
+
|
44
|
+
class << self
|
45
|
+
attr_accessor :project_key, :engine_key, :api_version, :verify_ssl_certs, :open_timeout, :read_timeout
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def self.api_url(api_base_url=nil, url='')
|
50
|
+
(api_base_url || @api_url) + url
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.ca_bundle_path
|
54
|
+
@ca_bundle_path
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.ca_bundle_path=(path)
|
58
|
+
@ca_bundle_path = path
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.request(method, url, params={})
|
62
|
+
|
63
|
+
if project_key =~ /\s/
|
64
|
+
raise TamberError.new('Your project key is invalid, as it contains ' \
|
65
|
+
'whitespace. (HINT: You can double-check your project key from the ' \
|
66
|
+
'Tamber dashboard. See https://dashboard.tamber.com to get your engine\'s key, or ' \
|
67
|
+
'email support@tamber.com if you have any questions.)')
|
68
|
+
end
|
69
|
+
|
70
|
+
if engine_key =~ /\s/
|
71
|
+
raise TamberError.new('Your engine key is invalid, as it contains ' \
|
72
|
+
'whitespace. (HINT: You can double-check your project key from the ' \
|
73
|
+
'Tamber dashboard. See https://dashboard.tamber.com to get your engine\'s key, or ' \
|
74
|
+
'email support@tamber.com if you have any questions.)')
|
75
|
+
end
|
76
|
+
|
77
|
+
if verify_ssl_certs
|
78
|
+
request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
79
|
+
:ssl_ca_file => @ca_bundle_path}
|
80
|
+
else
|
81
|
+
request_opts = {:verify_ssl => false}
|
82
|
+
unless @verify_ssl_warned
|
83
|
+
@verify_ssl_warned = true
|
84
|
+
$stderr.puts("WARNING: Running without SSL cert verification. " \
|
85
|
+
"You should never do this in production. " \
|
86
|
+
"Execute 'Tamber.verify_ssl_certs = true' to enable verification.")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
url = @api_url + url
|
91
|
+
|
92
|
+
case method.to_s.downcase.to_sym
|
93
|
+
when :get, :head, :delete
|
94
|
+
# Make params into GET parameters
|
95
|
+
url += "#{URI.parse(url).query ? '&' : '?'}#{Util.encode_parameters(params)}" if params && params.any?
|
96
|
+
payload = nil
|
97
|
+
else
|
98
|
+
payload = Util.encode_parameters(params)
|
99
|
+
end
|
100
|
+
|
101
|
+
request_opts.update(:headers => request_headers(project_key, engine_key, method),
|
102
|
+
:method => method, :open_timeout => open_timeout,
|
103
|
+
:payload => payload, :url => url, :timeout => read_timeout)
|
104
|
+
|
105
|
+
response = execute_request_with_rescues(request_opts)
|
106
|
+
|
107
|
+
[parse(response)]
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
def self.request_headers(pkey, ekey, method)
|
113
|
+
pkey ||= ''
|
114
|
+
ekey ||= ''
|
115
|
+
encoded_key = Base64.encode64(pkey + ':' + ekey)
|
116
|
+
headers = {
|
117
|
+
:user_agent => "Tamber/v1 RubyBindings/#{Tamber::VERSION}",
|
118
|
+
:authorization => "Basic "+encoded_key,
|
119
|
+
:content_type => 'application/x-www-form-urlencoded'
|
120
|
+
}
|
121
|
+
|
122
|
+
headers[:tamber_version] = api_version if api_version
|
123
|
+
|
124
|
+
begin
|
125
|
+
headers.update(:x_tamber_client_user_agent => JSON.generate(user_agent))
|
126
|
+
rescue => e
|
127
|
+
headers.update(:x_tamber_client_raw_user_agent => user_agent.inspect,
|
128
|
+
:error => "#{e} (#{e.class})")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.user_agent
|
133
|
+
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
134
|
+
|
135
|
+
{
|
136
|
+
:bindings_version => Tamber::VERSION,
|
137
|
+
:lang => 'ruby',
|
138
|
+
:lang_version => lang_version,
|
139
|
+
:platform => RUBY_PLATFORM,
|
140
|
+
:engine => defined?(RUBY_ENGINE) ? RUBY_ENGINE : '',
|
141
|
+
:publisher => 'tamber',
|
142
|
+
:hostname => Socket.gethostname,
|
143
|
+
}
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.general_api_error(rbody)
|
148
|
+
TamberError.new("Invalid response object from API: "+rbody.inspect)
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.handle_restclient_error(e, request_opts)
|
152
|
+
parse(e)
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.execute_request(opts)
|
156
|
+
RestClient::Request.execute(opts)
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.parse(response)
|
160
|
+
begin
|
161
|
+
response = JSON.parse(response.body)
|
162
|
+
if response["success"]
|
163
|
+
response = response["result"]
|
164
|
+
else
|
165
|
+
raise TamberError.new("Error: "+response["error"])
|
166
|
+
end
|
167
|
+
rescue JSON::ParserError
|
168
|
+
raise general_api_error(response.body)
|
169
|
+
end
|
170
|
+
Util.symbolize_names(response)
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def self.execute_request_with_rescues(request_opts)
|
176
|
+
# response = execute_request(request_opts)
|
177
|
+
begin
|
178
|
+
response = execute_request(request_opts)
|
179
|
+
rescue SocketError => e
|
180
|
+
response = handle_restclient_error(e, request_opts)
|
181
|
+
rescue NoMethodError => e
|
182
|
+
# Work around RestClient bug
|
183
|
+
if e.message =~ /\WRequestFailed\W/
|
184
|
+
raise TamberError.new('Error: Unexpected HTTP response code')
|
185
|
+
else
|
186
|
+
raise
|
187
|
+
end
|
188
|
+
rescue RestClient::ExceptionWithResponse => e
|
189
|
+
puts "ExceptionWithResponse: #{e}"
|
190
|
+
if e.response
|
191
|
+
puts "e.response"
|
192
|
+
parse(e.response)
|
193
|
+
else
|
194
|
+
response = handle_restclient_error(e, request_opts)
|
195
|
+
end
|
196
|
+
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
197
|
+
response = handle_restclient_error(e, request_opts)
|
198
|
+
end
|
199
|
+
|
200
|
+
response
|
201
|
+
end
|
202
|
+
end
|
data/tamber.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
|
+
|
3
|
+
require 'tamber/version'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = 'tamber'
|
7
|
+
s.version = Tamber::VERSION
|
8
|
+
s.required_ruby_version = '>= 1.9.3'
|
9
|
+
s.summary = 'Ruby bindings for the Tamber API'
|
10
|
+
s.description = 'Tamber is the easiest way to put head-scratchingly accurate, real time recommendations in your app. See https://tamber.com for details.'
|
11
|
+
s.homepage = 'https://tamber.com/docs/api'
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.authors = ['Alexi Robbins', 'Mark Canning']
|
14
|
+
s.email = ['alexi@tamber.com', 'argusdusty@tamber.com']
|
15
|
+
|
16
|
+
s.add_dependency('rest-client', '~> 1.4')
|
17
|
+
s.add_dependency('json', '~> 1.8.1')
|
18
|
+
s.add_dependency('activesupport', '~> 4.2.4')
|
19
|
+
|
20
|
+
s.add_development_dependency('mocha', '~> 0.13.2')
|
21
|
+
s.add_development_dependency('shoulda', '~> 3.4.0')
|
22
|
+
s.add_development_dependency('test-unit')
|
23
|
+
s.add_development_dependency('rake')
|
24
|
+
|
25
|
+
# if Gem::Version.new(RUBY_VERSION.dup) > Gem::Version.new('2.0.0')
|
26
|
+
# s.add_development_dependency("byebug")
|
27
|
+
# s.add_development_dependency("pry")
|
28
|
+
# s.add_development_dependency("pry-byebug")
|
29
|
+
# end
|
30
|
+
|
31
|
+
s.files = `git ls-files`.split("\n")
|
32
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
33
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
34
|
+
s.require_paths = ['lib']
|
35
|
+
end
|