nest_connect 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +58 -0
- data/README.md +35 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/nest_connect +30 -0
- data/bin/setup +8 -0
- data/lib/nest_connect/api/adapter/streaming_net_http.rb +177 -0
- data/lib/nest_connect/api/api.rb +38 -0
- data/lib/nest_connect/api/authorize.rb +55 -0
- data/lib/nest_connect/api/devices/camera.rb +41 -0
- data/lib/nest_connect/api/devices/protect.rb +33 -0
- data/lib/nest_connect/api/devices/structure.rb +41 -0
- data/lib/nest_connect/api/devices/thermostat.rb +41 -0
- data/lib/nest_connect/api/stream.rb +25 -0
- data/lib/nest_connect/chunk_parser.rb +66 -0
- data/lib/nest_connect/config_store.rb +53 -0
- data/lib/nest_connect/devices/camera.rb +60 -0
- data/lib/nest_connect/devices/protect.rb +49 -0
- data/lib/nest_connect/devices/structure.rb +85 -0
- data/lib/nest_connect/devices/thermostat.rb +194 -0
- data/lib/nest_connect/global_config.rb +37 -0
- data/lib/nest_connect/version.rb +3 -0
- data/lib/nest_connect.rb +14 -0
- data/nest_connect.gemspec +33 -0
- metadata +183 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
module NestConnect
|
2
|
+
class ChunkParser
|
3
|
+
EVENT = -'event: '
|
4
|
+
DATA = -'data: '
|
5
|
+
|
6
|
+
def self.write(chunk)
|
7
|
+
unless chunk.empty?
|
8
|
+
new(chunk)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(chunk)
|
13
|
+
@raw_event_line, @raw_data_line = chunk.split("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
def event
|
17
|
+
event_line
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
JSON.parse(data_line, symbolize_names: true) || {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def thermostats
|
25
|
+
Device::Thermostat.from_hash_collection(thermostats_hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
def protects
|
29
|
+
Device::Protect.from_hash_collection(smoke_co_alarms_hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
def cameras
|
33
|
+
Device::Camera.from_hash_collection(cameras_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def data_hash
|
39
|
+
data.fetch(:data, {})
|
40
|
+
end
|
41
|
+
|
42
|
+
def devices_hash
|
43
|
+
data_hash.fetch(:devices, {})
|
44
|
+
end
|
45
|
+
|
46
|
+
def thermostats_hash
|
47
|
+
devices_hash.fetch(:thermostats, {})
|
48
|
+
end
|
49
|
+
|
50
|
+
def smoke_co_alarms_hash
|
51
|
+
devices_hash.fetch(:smoke_co_alarms, {})
|
52
|
+
end
|
53
|
+
|
54
|
+
def cameras_hash
|
55
|
+
devices_hash.fetch(:cameras, {})
|
56
|
+
end
|
57
|
+
|
58
|
+
def data_line
|
59
|
+
@raw_data_line.gsub(DATA, "")
|
60
|
+
end
|
61
|
+
|
62
|
+
def event_line
|
63
|
+
@raw_event_line.gsub(EVENT, "")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module NestConnect
|
4
|
+
class ConfigStore
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
data[key]
|
11
|
+
end
|
12
|
+
|
13
|
+
def save(key, value)
|
14
|
+
data[key] = value
|
15
|
+
|
16
|
+
find_or_create_directory
|
17
|
+
find_or_create_file
|
18
|
+
persist_data
|
19
|
+
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :path
|
26
|
+
|
27
|
+
def find_or_create_directory
|
28
|
+
Dir.mkdir(pathname.dirname) unless Dir.exist?(pathname.dirname)
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_or_create_file
|
32
|
+
File.new(path, "w") unless File.exists?(path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def persist_data
|
36
|
+
File.open(path, "w") { |f| f.write(data.to_yaml) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def pathname
|
40
|
+
Pathname.new(path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def data
|
44
|
+
@_data ||= load_data
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_data
|
48
|
+
YAML.load(File.read(path)) || {}
|
49
|
+
rescue
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module NestConnect
|
2
|
+
class Device
|
3
|
+
class Camera
|
4
|
+
def self.from_hash_collection(hash)
|
5
|
+
hash.values.map { |value| new(value) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(api_class: NestConnect::API::Devices::Camera, **args)
|
9
|
+
@api_class = api_class
|
10
|
+
args.each do |key, value|
|
11
|
+
instance_variable_set("@#{key}", value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reload
|
16
|
+
api_runner.get.body.each do |key, value|
|
17
|
+
instance_variable_set("@#{key}", value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader(
|
22
|
+
:device_id,
|
23
|
+
:software_version,
|
24
|
+
:structure_id,
|
25
|
+
:where_id,
|
26
|
+
:where_name,
|
27
|
+
:name,
|
28
|
+
:name_long,
|
29
|
+
:is_online,
|
30
|
+
:is_audio_input_enabled,
|
31
|
+
:last_is_online_change,
|
32
|
+
:is_video_history_enabled,
|
33
|
+
:web_url,
|
34
|
+
:app_url,
|
35
|
+
:is_public_share_enabled,
|
36
|
+
:activity_zones,
|
37
|
+
:public_share_url,
|
38
|
+
:snapshot_url,
|
39
|
+
:last_event
|
40
|
+
)
|
41
|
+
|
42
|
+
attr_reader :is_streaming
|
43
|
+
|
44
|
+
def is_streaming=(value)
|
45
|
+
normalized_value = !!value
|
46
|
+
|
47
|
+
api_runner.put({is_streaming: normalized_value})
|
48
|
+
@is_streaming = normalized_value
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :api_class
|
54
|
+
|
55
|
+
def api_runner
|
56
|
+
api_class.new(device_id)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module NestConnect
|
2
|
+
class Device
|
3
|
+
class Protect
|
4
|
+
def self.from_hash_collection(hash)
|
5
|
+
hash.values.map { |value| new(value) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(api_class: NestConnect::API::Devices::Protect, **args)
|
9
|
+
@api_class = api_class
|
10
|
+
args.each do |key, value|
|
11
|
+
instance_variable_set("@#{key}", value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reload
|
16
|
+
api_runner.get.body.each do |key, value|
|
17
|
+
instance_variable_set("@#{key}", value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader(
|
22
|
+
:battery_health,
|
23
|
+
:co_alarm_state,
|
24
|
+
:device_id,
|
25
|
+
:is_manual_test_active,
|
26
|
+
:is_online,
|
27
|
+
:last_connection,
|
28
|
+
:last_manual_test_time,
|
29
|
+
:locale,
|
30
|
+
:name,
|
31
|
+
:name_long,
|
32
|
+
:smoke_alarm_state,
|
33
|
+
:software_version,
|
34
|
+
:structure_id,
|
35
|
+
:ui_color_state,
|
36
|
+
:where_id,
|
37
|
+
:where_name
|
38
|
+
)
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :api_class
|
43
|
+
|
44
|
+
def api_runner
|
45
|
+
api_class.new(device_id)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module NestConnect
|
2
|
+
class Device
|
3
|
+
class Structure
|
4
|
+
def self.from_hash_collection(hash)
|
5
|
+
hash.values.map { |value| new(value) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(api_class: NestConnect::API::Devices::Structure, **args)
|
9
|
+
@api_class = api_class
|
10
|
+
args.each do |key, value|
|
11
|
+
instance_variable_set("@#{key}", value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reload
|
16
|
+
api_runner.get.body.each do |key, value|
|
17
|
+
instance_variable_set("@#{key}", value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader(
|
22
|
+
:co_alarm_state,
|
23
|
+
:country_code,
|
24
|
+
:eta_begin,
|
25
|
+
:peak_period_end_time,
|
26
|
+
:peak_period_start_time,
|
27
|
+
:postal_code,
|
28
|
+
:rhr_enrollment,
|
29
|
+
:smoke_alarm_state,
|
30
|
+
:structure_id,
|
31
|
+
:time_zone,
|
32
|
+
:wheres,
|
33
|
+
:wwn_security_state
|
34
|
+
)
|
35
|
+
|
36
|
+
def thermostats
|
37
|
+
@thermostats.to_a.map do |device_id|
|
38
|
+
Device::Thermostat.new(device_id: device_id)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def protects
|
43
|
+
@smoke_alarm_state.to_a.map do |device_id|
|
44
|
+
Device::Protect.new(device_id: device_id)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def cameras
|
49
|
+
@cameras.to_a.map do |device_id|
|
50
|
+
Device::Camera.new(device_id: device_id)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
AWAY_VALUES = ['home', 'away']
|
55
|
+
|
56
|
+
attr_reader :away
|
57
|
+
|
58
|
+
def away=(value)
|
59
|
+
unless AWAY_VALUES.include?(value)
|
60
|
+
raise ValueError.new("away must be #{AWAY_VALUES}")
|
61
|
+
end
|
62
|
+
|
63
|
+
api_runner.put({away: value})
|
64
|
+
@away = value
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :name
|
68
|
+
|
69
|
+
def name=(value)
|
70
|
+
normalized_value = value.to_s
|
71
|
+
|
72
|
+
api_runner.put({name: normalized_value})
|
73
|
+
@name = normalized_value
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
attr_reader :api_class
|
79
|
+
|
80
|
+
def api_runner
|
81
|
+
api_class.new(structure_id)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module NestConnect
|
2
|
+
class RangeError < StandardError; end
|
3
|
+
class ValueError < StandardError; end
|
4
|
+
|
5
|
+
class Device
|
6
|
+
class Thermostat
|
7
|
+
def self.from_hash_collection(hash)
|
8
|
+
hash.values.map { |value| new(value) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(api_class: NestConnect::API::Devices::Thermostat, **args)
|
12
|
+
@api_class = api_class
|
13
|
+
args.each do |key, value|
|
14
|
+
instance_variable_set("@#{key}", value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def reload
|
19
|
+
api_runner.get.body.each do |key, value|
|
20
|
+
instance_variable_set("@#{key}", value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
TARGET_TEMPERATURE_F_RANGE = (50..90)
|
25
|
+
|
26
|
+
attr_reader :target_temperature_f
|
27
|
+
|
28
|
+
def target_temperature_f=(value)
|
29
|
+
normalized_value = value.round
|
30
|
+
|
31
|
+
unless TARGET_TEMPERATURE_F_RANGE.include?(normalized_value)
|
32
|
+
raise RangeError.new("target_temperature_f must be between #{TARGET_TEMPERATURE_F_RANGE}")
|
33
|
+
end
|
34
|
+
|
35
|
+
api_runner.put({target_temperature_f: normalized_value})
|
36
|
+
@target_temperature_f = normalized_value
|
37
|
+
end
|
38
|
+
|
39
|
+
TARGET_TEMPERATURE_C_RANGE = (9..30)
|
40
|
+
|
41
|
+
attr_reader :target_temperature_c
|
42
|
+
|
43
|
+
def target_temperature_c=(value)
|
44
|
+
normalized_value = (value * 2).round / 2.0
|
45
|
+
|
46
|
+
unless TARGET_TEMPERATURE_C_RANGE.include?(normalized_value)
|
47
|
+
raise RangeError.new("target_temperature_c must be between #{TARGET_TEMPERATURE_C_RANGE}")
|
48
|
+
end
|
49
|
+
|
50
|
+
api_runner.put({target_temperature_c: normalized_value})
|
51
|
+
@target_temperature_c = normalized_value
|
52
|
+
end
|
53
|
+
|
54
|
+
attr_reader :fan_timer_active
|
55
|
+
|
56
|
+
def fan_timer_active=(value)
|
57
|
+
normalized_value = !!value
|
58
|
+
|
59
|
+
api_runner.put({fan_timer_active: normalized_value})
|
60
|
+
@fan_timer_active = normalized_value
|
61
|
+
end
|
62
|
+
|
63
|
+
FAN_TIMER_DURATION_VALUES = [15, 30, 45, 60, 120, 240, 480, 720]
|
64
|
+
|
65
|
+
attr_reader :fan_timer_duration
|
66
|
+
|
67
|
+
def fan_timer_duration=(value)
|
68
|
+
unless FAN_TIMER_DURATION_VALUES.include?(value)
|
69
|
+
raise ValueError.new("fan_timer_duration must be #{FAN_TIMER_DURATION_VALUES}")
|
70
|
+
end
|
71
|
+
|
72
|
+
api_runner.put({fan_timer_duration: value})
|
73
|
+
@fan_timer_duration = value
|
74
|
+
end
|
75
|
+
|
76
|
+
HVAC_MODE_VALUES = ['heat', 'cool', 'heat-cool', 'eco', 'off']
|
77
|
+
|
78
|
+
attr_reader :hvac_mode
|
79
|
+
|
80
|
+
def hvac_mode=(value)
|
81
|
+
unless HVAC_MODE_VALUES.include?(value)
|
82
|
+
raise ValueError.new("hvac_mode must be #{HVAC_MODE_VALUES}")
|
83
|
+
end
|
84
|
+
|
85
|
+
api_runner.put({hvac_mode: value})
|
86
|
+
@hvac_mode = value
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_reader :label
|
90
|
+
|
91
|
+
def label=(value)
|
92
|
+
normalized_value = value.to_s
|
93
|
+
|
94
|
+
api_runner.put({label: normalized_value})
|
95
|
+
@label = normalized_value
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_reader :target_temperature_high_c
|
99
|
+
|
100
|
+
def target_temperature_high_c=(value)
|
101
|
+
normalized_value = (value * 2).round / 2.0
|
102
|
+
|
103
|
+
api_runner.put({target_temperature_high_c: normalized_value})
|
104
|
+
@target_temperature_high_c = normalized_value
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :target_temperature_low_c
|
108
|
+
|
109
|
+
def target_temperature_low_c=(value)
|
110
|
+
normalized_value = (value * 2).round / 2.0
|
111
|
+
|
112
|
+
api_runner.put({target_temperature_low_c: normalized_value})
|
113
|
+
@target_temperature_low_c = normalized_value
|
114
|
+
end
|
115
|
+
|
116
|
+
attr_reader :target_temperature_high_f
|
117
|
+
|
118
|
+
def target_temperature_high_f=(value)
|
119
|
+
normalized_value = value.round
|
120
|
+
|
121
|
+
api_runner.put({target_temperature_high_f: normalized_value})
|
122
|
+
@target_temperature_high_f = normalized_value
|
123
|
+
end
|
124
|
+
|
125
|
+
attr_reader :target_temperature_low_f
|
126
|
+
|
127
|
+
def target_temperature_low_f=(value)
|
128
|
+
normalized_value = value.round
|
129
|
+
|
130
|
+
api_runner.put({target_temperature_low_f: normalized_value})
|
131
|
+
@target_temperature_low_f = normalized_value
|
132
|
+
end
|
133
|
+
|
134
|
+
TEMPERATURE_SCALE_VALUES = ['C', 'F']
|
135
|
+
|
136
|
+
attr_reader :temperature_scale
|
137
|
+
|
138
|
+
def temperature_scale=(value)
|
139
|
+
unless TEMPERATURE_SCALE_VALUES.include?(value)
|
140
|
+
raise ValueError.new("temperature_scale must be #{TEMPERATURE_SCALE_VALUES}")
|
141
|
+
end
|
142
|
+
|
143
|
+
api_runner.put({temperature_scale: value})
|
144
|
+
@temperature_scale = value
|
145
|
+
end
|
146
|
+
|
147
|
+
attr_reader(
|
148
|
+
:ambient_temperature_c,
|
149
|
+
:ambient_temperature_f,
|
150
|
+
:can_cool,
|
151
|
+
:can_heat,
|
152
|
+
:device_id,
|
153
|
+
:eco_temperature_high_c,
|
154
|
+
:eco_temperature_high_f,
|
155
|
+
:eco_temperature_low_c,
|
156
|
+
:eco_temperature_low_f,
|
157
|
+
:fan_timer_duration,
|
158
|
+
:fan_timer_timeout,
|
159
|
+
:has_fan,
|
160
|
+
:has_leaf,
|
161
|
+
:humidity,
|
162
|
+
:hvac_state,
|
163
|
+
:is_locked,
|
164
|
+
:is_online,
|
165
|
+
:is_using_emergency_heat,
|
166
|
+
:last_connection,
|
167
|
+
:locale,
|
168
|
+
:locked_temp_max_c,
|
169
|
+
:locked_temp_max_f,
|
170
|
+
:locked_temp_min_c,
|
171
|
+
:locked_temp_min_f,
|
172
|
+
:name,
|
173
|
+
:name_long,
|
174
|
+
:previous_hvac_mode,
|
175
|
+
:software_version,
|
176
|
+
:structure_id,
|
177
|
+
:sunlight_correction_active,
|
178
|
+
:sunlight_correction_enabled,
|
179
|
+
:time_to_target,
|
180
|
+
:time_to_target_training,
|
181
|
+
:where_id,
|
182
|
+
:where_name
|
183
|
+
)
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
attr_reader :api_class
|
188
|
+
|
189
|
+
def api_runner
|
190
|
+
api_class.new(device_id)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module NestConnect
|
2
|
+
class GlobalConfig
|
3
|
+
DEFAULT_PATH = ENV["HOME"] + '/.nest_connect/config'
|
4
|
+
|
5
|
+
unless defined? @@path
|
6
|
+
@@path = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.path=(new_path)
|
10
|
+
@@path = new_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.path
|
14
|
+
@@path || DEFAULT_PATH
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(store = nil)
|
18
|
+
@store = store || ConfigStore.new(self.class.path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def access_token
|
22
|
+
@_access_token ||= store[:access_token] || configure_access_token
|
23
|
+
end
|
24
|
+
|
25
|
+
def access_token=(token)
|
26
|
+
store.save(:access_token, token)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :store
|
32
|
+
|
33
|
+
def configure_access_token
|
34
|
+
raise 'please configure your access token first by running nest_connect authorize'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/nest_connect.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module NestConnect
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'nest_connect/version'
|
7
|
+
require 'nest_connect/global_config'
|
8
|
+
require 'nest_connect/config_store'
|
9
|
+
require 'nest_connect/api/api'
|
10
|
+
require 'nest_connect/chunk_parser'
|
11
|
+
require 'nest_connect/devices/camera'
|
12
|
+
require 'nest_connect/devices/protect'
|
13
|
+
require 'nest_connect/devices/structure'
|
14
|
+
require 'nest_connect/devices/thermostat'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "nest_connect/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "nest_connect"
|
8
|
+
spec.version = NestConnect::VERSION
|
9
|
+
spec.authors = ["Karl Entwistle"]
|
10
|
+
spec.email = ["karl@entwistle.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Simple API Wrapper for Nest Thermostats}
|
13
|
+
spec.homepage = "https://github.com/karlentwistle/nest_connect"
|
14
|
+
|
15
|
+
# Specify which files should be added to the gem when it is released.
|
16
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
17
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
18
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_dependency 'faraday', '~> 0.15'
|
25
|
+
spec.add_dependency 'faraday_middleware', '~> 0.12'
|
26
|
+
spec.add_dependency 'thor', '~> 0.20'
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
29
|
+
spec.add_development_dependency "byebug"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
32
|
+
spec.add_development_dependency "webmock"
|
33
|
+
end
|