cellular 2.0.0 → 2.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3fdd4bd856508028b2de1f016627e9a107be0dd4
4
- data.tar.gz: a50db77596d53823b496506604356532e9519096
3
+ metadata.gz: a97fa1c32bf2c1aea85c36bd15bb489b9aaa20d9
4
+ data.tar.gz: a3190fd32b63a7cf284228d0b37481429ce30da4
5
5
  SHA512:
6
- metadata.gz: 1670df114c490aae52f7ad804656c4e3d538929f07fa7cbda5121466a4cfe637b3dcec5d39bb5c80e0a575e691842b8734bbe925011195b31a14d97dd4b746b8
7
- data.tar.gz: 9403f6ab944a9e0bba7df7b26a0e18c334f8a9bf16635c1cf4835573070aa1161c54814adc84e385fc1bac203097a9afddc0c8a83c36e4ee5e28afcdc0373bbe
6
+ metadata.gz: 359c6728df2bd17dafc5be5d0f04704ab7a394084ee3e0ace41f112ef48733c9883cd4ad08654a83c03d83a15d06b1fa43e215afb61d3fe628cf8f07118f310c
7
+ data.tar.gz: 610ac72f15d403b628dd60cdd70ffcb301dea9297402ec6c0d6c00ec0edfae128bfd962837c14993bffcf1dc95a0c1e6d6295772ae57c32682603f0c174e541c
data/.travis.yml CHANGED
@@ -2,4 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
4
  - 2.1.0
5
+ - 2.2.2
6
+ - 2.3.0
5
7
  script: bundle exec rake spec
data/README.md CHANGED
@@ -36,7 +36,7 @@ Or install it yourself as:
36
36
  Cellular.configure do |config|
37
37
  config.username = 'username'
38
38
  config.password = 'password'
39
- config.backend = Cellular::Backends::Sendega
39
+ config.backend = Cellular::Backends::Sendega
40
40
  config.sender = 'Default custom sender'
41
41
  config.country_code = 'NO'
42
42
  end
@@ -48,8 +48,9 @@ interface to interact with queue backends. Read appropriate documentation to set
48
48
 
49
49
  ### Available Backends
50
50
 
51
- * [CoolSMS](http://coolsms.com/)
52
- * [Sendega](http://sendega.com/)
51
+ * [Cellular::Backends::CoolSMS](http://coolsms.com/)
52
+ * [Cellular::Backends::Sendega](http://sendega.com/)
53
+ * [Cellular::Backends::Twilio](http://twilio.com/)
53
54
  * Log (logs to `$stdout`)
54
55
  * Test (adds messages to `Cellular.deliveries`)
55
56
 
@@ -60,8 +61,8 @@ The options supported may differ between backends.
60
61
 
61
62
  ```ruby
62
63
  sms = Cellular::SMS.new(
63
- recipient: '47xxxxxxxx',
64
- sender: 'Custom sender',
64
+ recipient: '+47xxxxxxxx', # Valid international format
65
+ sender: '+370xxxxxxxx',
65
66
  message: 'This is an SMS message',
66
67
  price: 0,
67
68
  country_code: 'NO' # defaults to Cellular.config.country_code
@@ -73,8 +74,8 @@ For use with multiple recipients in one request use:
73
74
 
74
75
  ```ruby
75
76
  sms = Cellular::SMS.new(
76
- recipients: ['47xxxxxxx1','47xxxxxxx2','47xxxxxxx3'],
77
- sender: 'Custom sender',
77
+ recipients: ['+47xxxxxxx1','+47xxxxxxx2','+47xxxxxxx3'],
78
+ sender: '+370xxxxxxxx',
78
79
  message: 'This is an SMS message',
79
80
  price: 0,
80
81
  country_code: 'NO' # defaults to Cellular.config.country_code
@@ -92,8 +93,8 @@ and are concerned that it might time out or something. To use it, just call
92
93
 
93
94
  ```ruby
94
95
  sms = Cellular::SMS.new(
95
- recipient: '47xxxxxxxx',
96
- sender: 'Custom sender',
96
+ recipient: '+47xxxxxxxx',
97
+ sender: '+47xxxxxxxx',
97
98
  message: 'This is an SMS message'
98
99
  )
99
100
 
@@ -113,21 +114,30 @@ Just call `deliver_async(wait_until: timestamp)` or `deliver_async(wait: time)`
113
114
 
114
115
  ```ruby
115
116
  sms = Cellular::SMS.new(
116
- recipient: '47xxxxxxxx',
117
- sender: 'Custom sender',
117
+ recipient: '+47xxxxxxxx',
118
+ sender: '+47xxxxxxxx',
118
119
  message: 'This is an SMS message'
119
120
  )
120
121
 
121
122
  sms.deliver_async(wait_until: Date.tomorrow.noon)
122
123
  ```
123
124
 
125
+ ## Troubleshooting
126
+
127
+ If you are using Twilio as a backend, please make sure you add or (port)[https://www.twilio.com/help/faq/porting] a phone number to your account so, that you can use that as a sender option. You won't be able to send messages from any phone number unless you port it to Twilio.
128
+
129
+ Also, make sure phone numbers are in valid international format:
130
+ [`+47xxxxxx`, `+370xxxxx`]
131
+
124
132
  ## Contributing
125
133
 
126
134
  1. Fork it
127
- 2. Create your feature branch (`git checkout -b my-new-feature`)
128
- 3. Commit your changes (`git commit -am 'Add some feature'`)
129
- 4. Push to the branch (`git push origin my-new-feature`)
130
- 5. Create pull request
135
+ 2. Create your feature branch (`git checkout -b feature/my-new-feature`)
136
+ 3. Write your code and necessary tests
137
+ 4. Run your tests (`bundle exec rspec`)
138
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
139
+ 6. Push to the branch (`git push origin feature/my-new-feature`)
140
+ 7. Create pull request and be awesome!
131
141
 
132
142
 
133
143
  ## Credits
data/cellular.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.name = 'cellular'
10
10
  gem.version = Cellular::VERSION
11
11
  gem.authors = ['Sindre Moen', 'Tim Kurvers']
12
- gem.email = ['johannes@hyper.no']
12
+ gem.email = ['ruby@hyper.no']
13
13
  gem.description = %q{Sending and receiving SMSs through pluggable backends}
14
14
  gem.summary = %q{Sending and receiving SMSs through pluggable backends}
15
15
  gem.homepage = ''
@@ -25,8 +25,6 @@ Gem::Specification.new do |gem|
25
25
 
26
26
  gem.add_development_dependency 'pry', '~> 0.10'
27
27
 
28
- gem.add_development_dependency 'guard', '~> 2.6'
29
- gem.add_development_dependency 'guard-rspec', '~> 4.3'
30
28
  gem.add_development_dependency 'rake', '~> 10.3'
31
29
  gem.add_development_dependency 'webmock', '~> 1.19'
32
30
 
@@ -3,6 +3,7 @@ module Cellular
3
3
  autoload :Backend, 'cellular/backends/backend'
4
4
  autoload :CoolSMS, 'cellular/backends/cool_sms'
5
5
  autoload :Sendega, 'cellular/backends/sendega'
6
+ autoload :Twilio, 'cellular/backends/twilio'
6
7
  autoload :Log, 'cellular/backends/log'
7
8
  autoload :Test, 'cellular/backends/test'
8
9
  end
@@ -0,0 +1,77 @@
1
+ require 'httparty'
2
+
3
+ module Cellular
4
+ module Backends
5
+ class Twilio < Backend
6
+ # Documentation: https://www.twilio.com/docs/api/rest
7
+ API_VERSION = '2010-04-01'
8
+ BASE_URL = 'https://api.twilio.com/'
9
+ API_URL = BASE_URL + API_VERSION
10
+
11
+ HTTP_HEADERS = {
12
+ 'Accept' => 'application/json',
13
+ 'Accept-Charset' => 'utf-8',
14
+ 'User-Agent' => "cellular/#{Cellular::VERSION}" \
15
+ " (#{RUBY_ENGINE}/#{RUBY_PLATFORM}" \
16
+ " #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
17
+ }
18
+
19
+ def self.deliver(options = {})
20
+ request_queue = {}
21
+ recipients_batch(options).each_with_index do |recipient, index|
22
+ options[:batch] = recipient
23
+ request = HTTParty.post(
24
+ sms_url,
25
+ body: payload(options),
26
+ basic_auth: twilio_config,
27
+ headers: HTTP_HEADERS
28
+ )
29
+
30
+ request_queue[index] = {
31
+ recipient: options[:batch],
32
+ response: parse_response(request)
33
+ }
34
+ end
35
+
36
+ # return first response for now
37
+ request_queue[0][:response]
38
+ end
39
+
40
+ def self.parse_response(response)
41
+ [
42
+ response.code,
43
+ response.message
44
+ ]
45
+ end
46
+
47
+ def self.sms_url
48
+ "#{API_URL}/Accounts/#{twilio_config[:username]}/Messages"
49
+ end
50
+
51
+ def self.twilio_config
52
+ {
53
+ username: Cellular.config.username,
54
+ password: Cellular.config.password
55
+ }
56
+ end
57
+
58
+ def self.payload(options)
59
+ {
60
+ From: options[:sender],
61
+ To: options[:batch],
62
+ Body: options[:message],
63
+ MaxPrice: options[:price] || 0.50
64
+ }
65
+ end
66
+
67
+ def self.recipients_batch(options)
68
+ if options[:recipients].blank?
69
+ [options[:recipient]]
70
+ else
71
+ options[:recipients]
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -4,7 +4,7 @@ module Cellular
4
4
  class SMS
5
5
 
6
6
  attr_accessor :recipient, :sender, :message, :price, :country_code
7
- attr_accessor :recipients
7
+ attr_accessor :recipients, :delivery_status, :delivery_message
8
8
  def initialize(options = {})
9
9
  @backend = Cellular.config.backend
10
10
 
@@ -1,3 +1,3 @@
1
1
  module Cellular
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cellular::Backends::Twilio do
4
+
5
+ let(:recipient) { '+15005550004' }
6
+ let(:sender) { '+15005550006' }
7
+ let(:message) { 'This is an SMS message' }
8
+ let(:price) { 0.001 }
9
+
10
+ let(:options) {
11
+ {
12
+ recipient: recipient,
13
+ sender: sender,
14
+ message: message,
15
+ price: price
16
+ }
17
+ }
18
+
19
+ let(:auth) {
20
+ {
21
+ username: 'account_sid',
22
+ password: 'auth_token'
23
+ }
24
+ }
25
+
26
+ let(:payload) {
27
+ {
28
+ From: sender,
29
+ To: recipient,
30
+ Body: message,
31
+ MaxPrice: price
32
+ }
33
+ }
34
+
35
+ before do
36
+ Cellular.config.username = 'account_sid'
37
+ Cellular.config.password = 'auth_token'
38
+ Cellular.config.backend = Cellular::Backends::Twilio
39
+ end
40
+
41
+ describe '::deliver' do
42
+ before do
43
+ stub_request(:post, "https://account_sid:auth_token@api.twilio.com/2010-04-01/Accounts/account_sid/Messages").
44
+ to_return(:status => [201, "CREATED"], :body => fixture('backends/twilio/success.json'), :headers => {'Content-Type' => 'application/json'})
45
+ end
46
+
47
+ it 'does uses HTTParty to deliver an SMS' do
48
+ expect(HTTParty).to receive(:post).with(described_class::sms_url, body:
49
+ payload, headers: described_class::HTTP_HEADERS, basic_auth: described_class::twilio_config).and_call_original
50
+
51
+ described_class.deliver(options)
52
+ end
53
+
54
+ context 'when successful' do
55
+ it 'does return a status code and message' do
56
+ expect(described_class.deliver(options)).to eq([
57
+ 201,
58
+ 'CREATED'
59
+ ])
60
+ end
61
+ end
62
+
63
+ context 'when not successful' do
64
+ before do
65
+ stub_request(:post, "https://account_sid:auth_token@api.twilio.com/2010-04-01/Accounts/account_sid/Messages").
66
+ to_return(:status => [400, "BAD REQUEST"], :body => fixture('backends/twilio/failure.json'), :headers => {'Content-Type' => 'application/json'})
67
+ end
68
+
69
+ it 'does return a status code and message' do
70
+ expect(described_class.deliver(options)).to eq([
71
+ 400,
72
+ 'BAD REQUEST'
73
+ ])
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ describe '::twilio_config' do
80
+ it 'does return the config for twilio' do
81
+ expect(described_class.twilio_config).to eq(
82
+ {
83
+ username: 'account_sid',
84
+ password: 'auth_token'
85
+ })
86
+ end
87
+ end
88
+
89
+ describe '::sms_url' do
90
+ it 'does return the full sms gateway url' do
91
+ expect(described_class.sms_url).to eq(
92
+ "https://api.twilio.com/2010-04-01/Accounts/account_sid/Messages"
93
+ )
94
+ end
95
+ end
96
+
97
+ describe '::payload' do
98
+ it 'does return the request payload' do
99
+ options[:batch] = recipient
100
+ expect(described_class.payload(options)).to eq(payload)
101
+ end
102
+ end
103
+
104
+ describe '::parse_response' do
105
+ before do
106
+ subject { Object.new }
107
+ end
108
+
109
+ context 'when not successful' do
110
+ it 'does return the formatted success response' do
111
+ subject.stub(:code).and_return(201)
112
+ subject.stub(:message).and_return('CREATED')
113
+
114
+ expect(described_class.parse_response(subject)).to eq(
115
+ [
116
+ 201,
117
+ 'CREATED'
118
+ ]
119
+ )
120
+ end
121
+ end
122
+
123
+ context 'when not successful' do
124
+ it 'does return the formatted failed response' do
125
+ subject.stub(:code).and_return(400)
126
+ subject.stub(:message).and_return('BAD REQUEST')
127
+
128
+ expect(described_class.parse_response(subject)).to eq(
129
+ [
130
+ 400,
131
+ 'BAD REQUEST'
132
+ ]
133
+ )
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '::recipients_batch' do
139
+ it 'does wrap recipient option into a array' do
140
+ expect(described_class.recipients_batch({recipient: recipient}))
141
+ .to eq([recipient])
142
+ end
143
+ it 'does return recipients option as it is' do
144
+ expect(described_class.recipients_batch({recipients: [recipient,recipient]}))
145
+ .to eq([recipient,recipient])
146
+ end
147
+ end
148
+ end
@@ -4,21 +4,22 @@ describe Cellular::Jobs::AsyncMessenger do
4
4
  let(:sms_stub) { double "SMS", deliver: true }
5
5
  let(:sms_options) { { "recipient" => "12345678", "text" => "Foo" } }
6
6
 
7
+ before do
8
+ allow(Cellular::SMS).to receive(:new).and_return sms_stub
9
+ end
10
+
7
11
  it 'creates a new SMS object' do
8
12
  symbolized_sms_options = { recipient: "12345678", text: "Foo" }
9
13
 
10
- expect(Cellular::SMS).to receive(:new)
11
- .with(symbolized_sms_options)
12
- .and_return sms_stub
13
-
14
14
  subject.perform sms_options
15
+
16
+ expect(Cellular::SMS).to have_received(:new)
17
+ .with(symbolized_sms_options)
15
18
  end
16
19
 
17
20
  it "delivers the SMS" do
18
- allow(Cellular::SMS).to receive(:new).and_return sms_stub
19
-
20
- expect(sms_stub).to receive :deliver
21
-
22
21
  subject.perform sms_options
22
+
23
+ expect(sms_stub).to have_received :deliver
23
24
  end
24
25
  end
@@ -0,0 +1,10 @@
1
+ {
2
+ "TwilioResponse": {
3
+ "RestException": {
4
+ "Code": "21211",
5
+ "Message": "The 'To' number +4475703596201 is not a valid phone number.",
6
+ "MoreInfo": "https://www.twilio.com/docs/errors/21211",
7
+ "Status": "400"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "TwilioResponse": {
3
+ "Message": {
4
+ "Sid": "SM3576e58e202041bf8be28e4ef52cbcbc",
5
+ "DateCreated": "Mon, 25 Apr 2016 05:18:07 +0000",
6
+ "DateUpdated": "Mon, 25 Apr 2016 05:18:07 +0000",
7
+ "DateSent": "",
8
+ "AccountSid": "AC800d5bd49542346c71674b49851a1bbf",
9
+ "To": "+447570359620",
10
+ "From": "+15005550006",
11
+ "MessagingServiceSid": "",
12
+ "Body": "This is an SMS message",
13
+ "Status": "queued",
14
+ "NumSegments": "1",
15
+ "NumMedia": "0",
16
+ "Direction": "outbound-api",
17
+ "ApiVersion": "2010-04-01",
18
+ "Price": "",
19
+ "PriceUnit": "USD",
20
+ "ErrorCode": "",
21
+ "ErrorMessage": "",
22
+ "Uri": "/2010-04-01/Accounts/AC800d5bd49542346c71674b49851a1bbf/Messages/SM3576e58e202041bf8be28e4ef52cbcbc",
23
+ "SubresourceUris": {
24
+ "Media": "/2010-04-01/Accounts/AC800d5bd49542346c71674b49851a1bbf/Messages/SM3576e58e202041bf8be28e4ef52cbcbc/Media"
25
+ }
26
+ }
27
+ }
28
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cellular
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sindre Moen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-26 00:00:00.000000000 Z
12
+ date: 2016-04-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -67,34 +67,6 @@ dependencies:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0.10'
70
- - !ruby/object:Gem::Dependency
71
- name: guard
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - "~>"
75
- - !ruby/object:Gem::Version
76
- version: '2.6'
77
- type: :development
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - "~>"
82
- - !ruby/object:Gem::Version
83
- version: '2.6'
84
- - !ruby/object:Gem::Dependency
85
- name: guard-rspec
86
- requirement: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - "~>"
89
- - !ruby/object:Gem::Version
90
- version: '4.3'
91
- type: :development
92
- prerelease: false
93
- version_requirements: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: '4.3'
98
70
  - !ruby/object:Gem::Dependency
99
71
  name: rake
100
72
  requirement: !ruby/object:Gem::Requirement
@@ -167,7 +139,7 @@ dependencies:
167
139
  version: '0.9'
168
140
  description: Sending and receiving SMSs through pluggable backends
169
141
  email:
170
- - johannes@hyper.no
142
+ - ruby@hyper.no
171
143
  executables: []
172
144
  extensions: []
173
145
  extra_rdoc_files: []
@@ -176,7 +148,6 @@ files:
176
148
  - ".travis.yml"
177
149
  - CHANGELOG.md
178
150
  - Gemfile
179
- - Guardfile
180
151
  - LICENSE.md
181
152
  - README.md
182
153
  - Rakefile
@@ -188,6 +159,7 @@ files:
188
159
  - lib/cellular/backends/log.rb
189
160
  - lib/cellular/backends/sendega.rb
190
161
  - lib/cellular/backends/test.rb
162
+ - lib/cellular/backends/twilio.rb
191
163
  - lib/cellular/configuration.rb
192
164
  - lib/cellular/jobs.rb
193
165
  - lib/cellular/jobs/async_messenger.rb
@@ -199,6 +171,7 @@ files:
199
171
  - spec/cellular/backends/log_with_rails_spec.rb
200
172
  - spec/cellular/backends/sendega_spec.rb
201
173
  - spec/cellular/backends/test_spec.rb
174
+ - spec/cellular/backends/twilio_spec.rb
202
175
  - spec/cellular/configuration_spec.rb
203
176
  - spec/cellular/jobs/async_messenger_spec.rb
204
177
  - spec/cellular/logger_spec.rb
@@ -209,6 +182,8 @@ files:
209
182
  - spec/fixtures/backends/sendega/failure.xml
210
183
  - spec/fixtures/backends/sendega/service.wsdl
211
184
  - spec/fixtures/backends/sendega/success.xml
185
+ - spec/fixtures/backends/twilio/failure.json
186
+ - spec/fixtures/backends/twilio/success.json
212
187
  - spec/spec_helper.rb
213
188
  - spec/support/fixture.rb
214
189
  homepage: ''
@@ -230,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
205
  version: '0'
231
206
  requirements: []
232
207
  rubyforge_project:
233
- rubygems_version: 2.2.2
208
+ rubygems_version: 2.5.1
234
209
  signing_key:
235
210
  specification_version: 4
236
211
  summary: Sending and receiving SMSs through pluggable backends
@@ -240,6 +215,7 @@ test_files:
240
215
  - spec/cellular/backends/log_with_rails_spec.rb
241
216
  - spec/cellular/backends/sendega_spec.rb
242
217
  - spec/cellular/backends/test_spec.rb
218
+ - spec/cellular/backends/twilio_spec.rb
243
219
  - spec/cellular/configuration_spec.rb
244
220
  - spec/cellular/jobs/async_messenger_spec.rb
245
221
  - spec/cellular/logger_spec.rb
@@ -250,5 +226,7 @@ test_files:
250
226
  - spec/fixtures/backends/sendega/failure.xml
251
227
  - spec/fixtures/backends/sendega/service.wsdl
252
228
  - spec/fixtures/backends/sendega/success.xml
229
+ - spec/fixtures/backends/twilio/failure.json
230
+ - spec/fixtures/backends/twilio/success.json
253
231
  - spec/spec_helper.rb
254
232
  - spec/support/fixture.rb
data/Guardfile DELETED
@@ -1,23 +0,0 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- guard :rspec, cmd: 'bundle exec rspec', notification: false do
5
- watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
- watch('spec/spec_helper.rb') { "spec" }
8
-
9
- # Rails example
10
- watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
- watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
- watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
- watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
- watch('config/routes.rb') { "spec/routing" }
15
- watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
-
17
- # Capybara features specs
18
- watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
-
20
- # Turnip features and steps
21
- watch(%r{^spec/acceptance/(.+)\.feature$})
22
- watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
- end