boutique 0.0.9 → 0.0.10

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.
@@ -3,86 +3,40 @@ require File.expand_path('helper', File.dirname(__FILE__))
3
3
  class AppTest < BoutiqueTest
4
4
  include Rack::Test::Methods
5
5
 
6
- def test_redirect_to_paypal
7
- ebook_product.save
8
- get '/buy/ebook'
9
-
10
- purchase = Boutique::Purchase.first
11
- refute(purchase.nil?)
12
- assert(last_response.ok?)
13
- end
14
-
15
- def test_purchase_non_existing_product
16
- get '/buy/non-existing-product'
17
- assert(last_response.not_found?)
18
- end
19
-
20
- def test_notify
21
- product = ebook_product
22
- purchase = Boutique::Purchase.new
23
- product.purchases << purchase
24
- product.save
25
- refute(purchase.completed?)
26
- assert_nil(Pony.last_mail)
27
-
28
- post "/notify/#{purchase.boutique_id}?payment_status=Completed&txn_id=1337&receiver_email=#{Boutique.config.pp_email}&payer_email=john@mailinator.com&first_name=John"
6
+ def test_subscribe
7
+ list = new_list
8
+ post "/subscribe/#{list.key}", email: 'john@mailinator.com'
29
9
  assert(last_response.ok?)
30
-
31
- purchase.reload
32
- assert(purchase.completed?)
10
+ assert_equal(1, Boutique::Subscriber.count)
11
+ assert_equal(1, Boutique::Email.count)
33
12
  refute_nil(Pony.last_mail)
34
- assert_equal('1337', purchase.transaction_id)
35
- end
36
-
37
- def test_notify_not_found
38
- post "/notify/99-notfound"
39
- assert(last_response.not_found?)
13
+ subscriber = Boutique::Subscriber.first
14
+ refute(subscriber.confirmed?)
40
15
  end
41
16
 
42
- def test_recover
43
- purchase = ebook_purchase
44
- purchase.complete('1337', 'john@mailinator.com', 'John')
45
- purchase.save
46
- assert_nil(Pony.last_mail)
47
-
48
- post "/recover/ebook", 'email' => 'john@mailinator.com'
17
+ def test_confirm
18
+ list = new_list
19
+ subscriber = Boutique::Subscriber.create(
20
+ list_key: list.key, email: 'john@mailinator.com')
21
+ refute(subscriber.confirmed?)
22
+ post "/confirm/#{list.key}/#{subscriber.id}/#{subscriber.secret}"
49
23
  assert(last_response.ok?)
50
- assert_equal(purchase.boutique_id, last_response.body)
51
- refute_nil(Pony.last_mail)
24
+ subscriber = Boutique::Subscriber.get(subscriber.id)
25
+ assert(subscriber.confirmed?)
52
26
  end
53
27
 
54
- def test_recover_not_found
55
- post "/recover/99-notfound"
56
- assert(last_response.not_found?)
57
- end
58
-
59
- def test_record
60
- purchase = ebook_purchase
61
- get "/record/#{purchase.boutique_id}"
28
+ def test_unsubscribe
29
+ list = new_list
30
+ subscriber = Boutique::Subscriber.create(
31
+ list_key: list.key, email: 'john@mailinator.com', confirmed: true)
32
+ assert(subscriber.confirmed?)
33
+ post "/unsubscribe/#{list.key}/#{subscriber.id}/#{subscriber.secret}"
62
34
  assert(last_response.ok?)
63
-
64
- json = JSON.parse(last_response.body)
65
- assert(json['id'])
66
- assert_equal('ebook', json['code'])
67
- assert_equal('Ebook', json['name'])
68
- assert_equal(0, json['counter'])
69
- refute(json['completed'])
70
- end
71
-
72
- def test_record_not_found
73
- get "/record/99-notfound"
74
- assert(last_response.not_found?)
35
+ subscriber = Boutique::Subscriber.get(subscriber.id)
36
+ refute(subscriber.confirmed?)
75
37
  end
76
38
 
77
39
  private
78
- def ebook_purchase
79
- product = ebook_product
80
- purchase = Boutique::Purchase.new
81
- product.purchases << purchase
82
- product.save
83
- purchase
84
- end
85
-
86
40
  def app
87
41
  @app ||= Rack::Server.new.app
88
42
  end
@@ -3,18 +3,20 @@ require File.expand_path('helper', File.dirname(__FILE__))
3
3
  class ConfigTest < BoutiqueTest
4
4
  def test_db
5
5
  assert_equal('dev@localhost', Boutique.config.dev_email)
6
- assert_equal('LONGCERTID', Boutique.config.pem_cert_id)
7
- assert_equal(File.expand_path('../certs/private.pem', File.dirname(__FILE__)), Boutique.config.pem_private)
8
- assert_equal(File.expand_path('../certs/public.pem', File.dirname(__FILE__)), Boutique.config.pem_public)
9
- assert_equal(File.expand_path('../certs/private.pem', File.dirname(__FILE__)), Boutique.config.pem_private)
6
+ assert_equal(
7
+ 'sk_test_abcdefghijklmnopqrstuvwxyz',
8
+ Boutique.config.stripe_api_key)
10
9
  assert_equal('/download', Boutique.config.download_path)
11
- assert_equal(File.expand_path('../temp', File.dirname(__FILE__)), Boutique.config.download_dir)
12
- assert_equal('sqlite3', Boutique.config.db_adapter)
13
- assert_equal('localhost', Boutique.config.db_host)
14
- assert_equal('root', Boutique.config.db_username)
15
- assert_equal('secret', Boutique.config.db_password)
16
- assert_equal('db.sqlite3', Boutique.config.db_database)
17
- assert_equal('paypal_biz@mailinator.com', Boutique.config.pp_email)
18
- assert_equal('http://localhost', Boutique.config.pp_url)
10
+ assert_equal(
11
+ File.expand_path('../temp', File.dirname(__FILE__)),
12
+ Boutique.config.download_dir)
13
+ assert_equal({
14
+ adapter: 'sqlite3',
15
+ host: 'localhost',
16
+ username: 'root',
17
+ password: 'secret',
18
+ database: 'db.sqlite3'},
19
+ Boutique.config.db_options)
20
+ assert_equal({via: :sendmail}, Boutique.config.email_options)
19
21
  end
20
22
  end
@@ -0,0 +1,67 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'redcarpet'
3
+
4
+ class EmailerTest < BoutiqueTest
5
+ def setup
6
+ super
7
+ @list = new_list
8
+ @emailer = Boutique::Emailer.new(@list)
9
+ end
10
+
11
+ def test_render
12
+ @emailer.render(
13
+ 'intro.md.erb',
14
+ confirm_url: 'http://example.org/confirm',
15
+ unsubscribe_url: 'http://example.org/unsubscribe')
16
+ end
17
+
18
+ def test_blast
19
+ @emailer.blast('first.md.erb')
20
+ refute(Pony.last_mail)
21
+ assert_equal(0, Boutique::Email.count)
22
+
23
+ create_subscriber
24
+ @emailer.blast('first.md.erb')
25
+ mail = Pony.last_mail
26
+ assert_equal('john@mailinator.com', mail[:to])
27
+ assert_equal('learn-icon@example.com', mail[:from])
28
+ assert_equal('First Email', mail[:subject])
29
+ refute_nil(mail[:body])
30
+ assert_equal(1, Boutique::Email.count)
31
+
32
+ Pony.mail(nil)
33
+ @emailer.blast('first.md.erb')
34
+ assert_nil(Pony.last_mail)
35
+ assert_equal(1, Boutique::Email.count)
36
+ end
37
+
38
+ def test_drip
39
+ @emailer.drip
40
+ refute(Pony.last_mail)
41
+ assert_equal(0, Boutique::Email.count)
42
+
43
+ subscriber = create_subscriber
44
+ subscriber.drip_on = Date.today - 1
45
+ subscriber.save
46
+ assert_equal(0, subscriber.drip_day)
47
+ @emailer.drip
48
+ subscriber = Boutique::Subscriber.get(subscriber.id)
49
+ assert_equal(1, subscriber.drip_day)
50
+ refute_nil(Pony.last_mail)
51
+ assert_equal(1, Boutique::Email.count)
52
+ assert_equal('first', Boutique::Email.first.email_key)
53
+
54
+ Pony.mail(nil)
55
+ @emailer.drip
56
+ subscriber = Boutique::Subscriber.get(subscriber.id)
57
+ assert_equal(1, subscriber.drip_day)
58
+ assert_nil(Pony.last_mail)
59
+ assert_equal(1, Boutique::Email.count)
60
+ end
61
+
62
+ private
63
+ def create_subscriber
64
+ Boutique::Subscriber.create(
65
+ list_key: @list.key, email: 'john@mailinator.com', confirmed: true)
66
+ end
67
+ end
@@ -19,25 +19,24 @@ module Pony
19
19
  end
20
20
  end
21
21
 
22
- class BoutiqueTest < MiniTest::Unit::TestCase
22
+ class BoutiqueTest < MiniTest::Test
23
23
  def setup
24
24
  Boutique::Purchase.all.destroy
25
- Boutique::Product.all.destroy
25
+ Boutique::Subscriber.all.destroy
26
+ Boutique::Email.all.destroy
27
+ Boutique::List.reset_db
28
+ Boutique::Product.reset_db
26
29
  Boutique.configure(false) do |c|
27
- c.dev_email 'dev@localhost'
28
- c.pem_cert_id 'LONGCERTID'
29
- c.pem_private File.expand_path('../certs/private.pem', File.dirname(__FILE__))
30
- c.pem_public File.expand_path('../certs/public.pem', File.dirname(__FILE__))
31
- c.pem_paypal File.expand_path('../certs/paypal.pem', File.dirname(__FILE__))
32
- c.download_path '/download'
33
- c.download_dir File.expand_path('../temp', File.dirname(__FILE__))
34
- c.db_adapter 'sqlite3'
35
- c.db_host 'localhost'
36
- c.db_username 'root'
37
- c.db_password 'secret'
38
- c.db_database 'db.sqlite3'
39
- c.pp_email 'paypal_biz@mailinator.com'
40
- c.pp_url 'http://localhost'
30
+ c.dev_email 'dev@localhost'
31
+ c.stripe_api_key 'sk_test_abcdefghijklmnopqrstuvwxyz'
32
+ c.download_path '/download'
33
+ c.download_dir File.expand_path('../temp', File.dirname(__FILE__))
34
+ c.db_options(adapter: 'sqlite3',
35
+ host: 'localhost',
36
+ username: 'root',
37
+ password: 'secret',
38
+ database: 'db.sqlite3')
39
+ c.email_options(via: :sendmail)
41
40
  end
42
41
  Pony.mail(nil)
43
42
  end
@@ -47,6 +46,15 @@ class BoutiqueTest < MiniTest::Unit::TestCase
47
46
  end
48
47
 
49
48
  private
49
+ def new_list
50
+ Boutique.list('learn-icon') do |l|
51
+ l.from 'learn-icon@example.com'
52
+ l.emails File.expand_path('../emails', File.dirname(__FILE__))
53
+ l.url 'http://example.com'
54
+ end
55
+ Boutique::List['learn-icon']
56
+ end
57
+
50
58
  def ebook_product
51
59
  Boutique::Product.new(
52
60
  :code => 'ebook',
@@ -1,80 +1,88 @@
1
1
  require File.expand_path('helper', File.dirname(__FILE__))
2
2
 
3
3
  class ModelTest < BoutiqueTest
4
- def test_purchase_create
5
- product = ebook_product
6
- product.save
7
- count = Boutique::Purchase.count
8
- purchase = Boutique::Purchase.new
9
- product.purchases << purchase
10
- product.save
11
-
12
- assert_equal(count + 1, Boutique::Purchase.count)
13
- assert_equal(0, purchase.counter)
14
- assert_nil(purchase.transaction_id)
15
- assert_nil(purchase.completed_at)
16
- assert_nil(purchase.downloads)
17
- refute_nil(purchase.secret)
18
- refute_nil(purchase.created_at)
19
- refute(purchase.completed?)
4
+ def test_product
5
+ Boutique.product('icon-set') do |p|
6
+ p.from 'support@zincmade.com'
7
+ p.files [File.expand_path('../README.md', File.dirname(__FILE__))]
8
+ p.price 10.5
9
+ end
20
10
 
21
- purchase.complete('1', 'john@mailinator.com', 'John')
22
- purchase.save
23
- assert_equal('1', purchase.transaction_id)
24
- refute_nil(purchase.completed_at)
25
- assert(purchase.completed?)
26
- assert_match(%r(/download/[^/]+/README.md), purchase.downloads[0])
11
+ set = Boutique::Product['icon-set']
12
+ assert_equal('icon-set', set.key)
13
+ assert_equal(
14
+ File.expand_path('../README.md', File.dirname(__FILE__)),
15
+ set.files[0])
16
+ assert_equal(10.5, set.price)
17
+ assert_equal('support@zincmade.com', set.from)
18
+ end
27
19
 
28
- old_download = purchase.downloads[0]
29
- `rm #{Boutique.config.download_dir}#{old_download.sub(Boutique.config.download_path, '')}`
30
- purchase.maybe_refresh_downloads!
31
- refute_equal(old_download, purchase.downloads[0])
20
+ def test_list
21
+ list = new_list
22
+ assert_equal('learn-icon', list.key)
23
+ assert_equal('learn-icon@example.com', list.from)
24
+ assert_equal('http://example.com', list.url)
25
+ assert_equal(File.expand_path('../emails', File.dirname(__FILE__)), list.emails)
26
+ assert_equal("http://example.com?boutique=subscribe/learn-icon", list.subscribe_url)
27
+ end
32
28
 
33
- bid = purchase.boutique_id
34
- assert_equal(purchase.id, bid.split('-')[0].to_i)
35
- assert_equal(10, bid.split('-')[1].size)
29
+ def test_subscriber
30
+ list = new_list
31
+ subscriber = Boutique::Subscriber.new(
32
+ list_key: 'learn-icon',
33
+ email: 'john@mailinator.com')
34
+ subscriber.save
35
+ refute(subscriber.confirmed?)
36
+ refute_nil(subscriber.secret)
37
+ assert_equal(1, list.subscribers.count)
38
+ assert_equal(subscriber, list.subscribers.first)
39
+ assert_equal(0, subscriber.drip_day)
40
+ assert_equal(Date.today, subscriber.drip_on)
36
41
 
37
- form = purchase.paypal_form('http://localhost/notify')
38
- assert_equal('http://localhost', form['action'])
39
- assert_equal('_s-xclick', form['cmd'])
40
- refute_nil(form['encrypted'])
42
+ id, secret = subscriber.id, subscriber.secret
43
+ assert_equal(
44
+ "http://example.com?boutique=confirm/learn-icon/#{id}/#{secret}",
45
+ subscriber.confirm_url)
46
+ assert_equal(
47
+ "http://example.com?boutique=unsubscribe/learn-icon/#{id}/#{secret}",
48
+ subscriber.unsubscribe_url)
49
+ end
41
50
 
42
- purchase.send_mail
43
- assert_equal({
44
- :to => 'john@mailinator.com',
45
- :from => 'support@zincmade.com',
46
- :subject => 'Ebook Receipt',
47
- :body => "Thanks for purchasing Ebook! To download it, follow this link:\n\n" +
48
- " http://zincmade.com?b=#{purchase.boutique_id}\n\n" +
49
- "Please reply if you have any troubles.\n"
50
- }, Pony.last_mail)
51
+ def test_subscriber_email_validation
52
+ list = new_list
53
+ subscriber = Boutique::Subscriber.new(
54
+ list_key: 'learn-icon',
55
+ email: 'invalid-email')
56
+ refute(subscriber.valid?)
57
+ refute_empty(subscriber.errors[:email])
58
+ end
51
59
 
52
- json = JSON.parse(purchase.to_json)
53
- assert_equal(purchase.id, json['id'])
54
- assert_equal(2, json['counter'])
55
- assert(json['completed'])
56
- assert_equal('Ebook', json['name'])
57
- assert_equal('ebook', json['code'])
58
- refute_nil(json['downloads'])
60
+ def test_subscriber_list_key_validation
61
+ subscriber = Boutique::Subscriber.new(
62
+ list_key: 'invalid-list-key',
63
+ email: 'john@mailinator.com')
64
+ refute(subscriber.valid?)
65
+ refute_empty(subscriber.errors[:list_key])
59
66
  end
60
67
 
61
- def test_product_create
62
- count = Boutique::Product.count
63
- Boutique.product('icon-set') do |p|
64
- p.name 'Icon Set'
65
- p.files [File.expand_path('../README.md', File.dirname(__FILE__))]
66
- p.price 10.5
67
- p.return_url 'http://zincmade.com'
68
- p.support_email 'support@zincmade.com'
69
- end
70
- assert_equal(count + 1, Boutique::Product.count)
68
+ def test_subscriber_list_email_unique
69
+ list = new_list
70
+ attrs = {list_key: list.key, email: 'john@mailinator.com'}
71
+ Boutique::Subscriber.create(attrs)
72
+ subscriber = Boutique::Subscriber.new(attrs)
73
+ refute(subscriber.valid?)
74
+ refute_empty(subscriber.errors[:email])
75
+ end
71
76
 
72
- set = Boutique::Product.first(:code => 'icon-set')
73
- assert_equal('Icon Set', set.name)
74
- assert_equal(File.expand_path('../README.md', File.dirname(__FILE__)), set.files[0])
75
- assert_equal(10.5, set.price)
76
- assert_equal('http://zincmade.com', set.return_url)
77
- assert_equal('support@zincmade.com', set.support_email)
78
- assert_equal(0, set.purchases.size)
77
+ def test_email_unique
78
+ list = new_list
79
+ sub = Boutique::Subscriber.create(list_key: list.key, email: 'john@mailinator.com')
80
+ Boutique::Email.create(email_key: 'first', subscriber: sub)
81
+ email = Boutique::Email.new(email_key: 'first', subscriber: sub)
82
+ refute(email.valid?)
83
+ refute_empty(email.errors[:email_key])
84
+ sub2 = Boutique::Subscriber.create(list_key: list.key, email: 'jane@mailinator.com')
85
+ email = Boutique::Email.create(email_key: 'first', subscriber: sub2)
86
+ assert(email.valid?)
79
87
  end
80
88
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boutique
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: .
11
11
  cert_chain: []
12
- date: 2012-02-03 00:00:00.000000000 Z
12
+ date: 2013-09-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
16
- requirement: &70210798513600 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70210798513600
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: data_mapper
27
- requirement: &70210798513080 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *70210798513080
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: pony
38
- requirement: &70210798512520 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,10 +53,47 @@ dependencies:
43
53
  version: '0'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *70210798512520
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: tilt
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: preamble
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
47
94
  - !ruby/object:Gem::Dependency
48
95
  name: minitest
49
- requirement: &70210798512060 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
50
97
  none: false
51
98
  requirements:
52
99
  - - ! '>='
@@ -54,10 +101,31 @@ dependencies:
54
101
  version: '0'
55
102
  type: :development
56
103
  prerelease: false
57
- version_requirements: *70210798512060
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
58
110
  - !ruby/object:Gem::Dependency
59
111
  name: shotgun
60
- requirement: &70210798511540 !ruby/object:Gem::Requirement
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rack-test
128
+ requirement: !ruby/object:Gem::Requirement
61
129
  none: false
62
130
  requirements:
63
131
  - - ! '>='
@@ -65,9 +133,46 @@ dependencies:
65
133
  version: '0'
66
134
  type: :development
67
135
  prerelease: false
68
- version_requirements: *70210798511540
69
- description: A Sinatra module which accepts payments via PayPal and gives customers
70
- a secret URL to download your product.
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: dm-sqlite-adapter
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: redcarpet
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: A Sinatra app that adds product checkouts and drip emails support to
175
+ any websites (both UI + backend).
71
176
  email:
72
177
  - hugh@hughbien.com
73
178
  executables:
@@ -80,10 +185,11 @@ files:
80
185
  - config.ru
81
186
  - boutique
82
187
  - lib/boutique.rb
83
- - test/app_test.rb
84
- - test/config_test.rb
85
188
  - test/helper.rb
86
189
  - test/model_test.rb
190
+ - test/emailer_test.rb
191
+ - test/config_test.rb
192
+ - test/app_test.rb
87
193
  - ./boutique
88
194
  homepage: https://github.com/hughbien/boutique
89
195
  licenses: []
@@ -97,6 +203,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
203
  - - ! '>='
98
204
  - !ruby/object:Gem::Version
99
205
  version: '0'
206
+ segments:
207
+ - 0
208
+ hash: -412580643
100
209
  required_rubygems_version: !ruby/object:Gem::Requirement
101
210
  none: false
102
211
  requirements:
@@ -105,8 +214,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
214
  version: 1.3.6
106
215
  requirements: []
107
216
  rubyforge_project:
108
- rubygems_version: 1.8.11
217
+ rubygems_version: 1.8.23
109
218
  signing_key:
110
219
  specification_version: 3
111
- summary: Sinatra module for selling digital goods
220
+ summary: Sinatra app product checkouts and drip emails
112
221
  test_files: []