shopify-sinatra-app 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fccd4ff6faec2fcff66aed5c5fdf7f3893935cba839e21d2192065190891bb2c
4
- data.tar.gz: e29f14e3e7cdb0d7f21bbce7189c61178566c2931d52e00e0980000fe2dd8f8c
3
+ metadata.gz: 6e20ce69bc42bc9bc307d4a57867d6249fadd78d8a45cc78085271af499efbc3
4
+ data.tar.gz: dc0743abc76b5d92f6d14eeed9a1096611b6200f506d8f942e090ebaa77f78bf
5
5
  SHA512:
6
- metadata.gz: c08033567d98178683fd4a1153eeef3761eed574f7e3f303bc17cd38fec6d252ecd6126a1404d57ccbcbf8af3e5d74a8a8b8fdce7af0092e4b9d560a16de033b
7
- data.tar.gz: f09d42913d91dd1f502e3243536b960797acacb1dc95afaac0fd30ed3a530194536437310c0eccca99ed7acc887c725c5f9f7438f98eabb378da0da5bc783684
6
+ metadata.gz: bc5d771d614036bd2d966e33c1e98a98d1f539fd8922cccf5f948fd536128374a6b1aac3591e02109fb50f5ea987d88b2ebd92cd33dab5615843127eeb4904c5
7
+ data.tar.gz: 3d83a80b3d6df53d4441b25ecba9966bc16535c8dd71572dfdfd40823349eab9f1094bfaa00380fa65d05e31cfd31bf01dd77384f269441a65e5dc245ca1b8cf
data/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
1
  *.gem
2
2
  *.sqlite3
3
+ Gemfile.lock
4
+ example/Gemfile.lock
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ 0.5.0
2
+ -----
3
+ * replace webhook_session and webhook_job with shopify_webhook
4
+ * remove redis and resque as dependencies
5
+
1
6
  0.4.0
2
7
  -----
3
8
  * update to sinatra 2.0.1
data/README.md CHANGED
@@ -87,31 +87,26 @@ get '/products.json' do
87
87
  end
88
88
  ```
89
89
 
90
- **webhook_session** - This method is for an endpoint that recieves a webhook from Shopify. Webhooks are a great way to keep your app in sync with a shop's data without polling. You can read more about webhooks [here](http://docs.shopify.com/api/tutorials/using-webhooks). This method also takes a block of code and yields the `webhook_data` as a hash (note only works for json webhooks, don't use xml). Here is an example that listens to an order creation webhook:
90
+ **shopify_webhook** - This method is for an endpoint that receives a webhook from Shopify. Webhooks are a great way to keep your app in sync with a shop's data without polling. You can read more about webhooks [here](http://docs.shopify.com/api/tutorials/using-webhooks). This method also takes a block and yields the `webhook_body` as a hash (note only works for json webhooks, don't use xml). Here is an example that listens to an order creation webhook:
91
91
 
92
92
  ```ruby
93
93
  post '/order.json' do
94
- webhook_session do |webhook_data|
94
+ shopify_webhook do |webhook_data|
95
95
  # do something with the data
96
96
  end
97
97
  end
98
98
  ```
99
99
 
100
- **webhook_job** - Its impossible to control the flow of webhooks to your app from Shopify especially if a larger store installs your app or if a shop has a flash sale. To prevent your app from getting overloaded with webhook requests it is usually a good idea to process webhooks in a background queue and return a `200` to Shopify immediately. This method provides this functionality using redis and resque. This method takes the name of a job class whose perform method expects a `shop_name`, `shop_token` and the `webhook_data` as a hash. The session method is useful for prototpying and experimenting but production apps should use `webhook_job`. Here is an example:
100
+ Note this method does not active a Shopify session by default but the current_shop* methods still work. It is not advised but if you want to handle the webhook in a web request you will need to activate the ShopifyAPI session manually:
101
101
 
102
102
  ```ruby
103
- post '/order.json' do
104
- webhook_job(OrderWebhookJob)
105
- end
103
+ shop = Shop.find_by(name: current_shop_name)
104
+ api_session = ShopifyAPI::Session.new(shop.name, shop.token)
105
+ ShopifyAPI::Base.activate_session(api_session)
106
+ ```
106
107
 
107
- class OrderWebhookJob
108
- @queue = :default
108
+ It's impossible to control the flow of webhooks to your app from Shopify especially if a larger store installs your app or if a shop has a flash sale. To prevent your app from getting overloaded with webhook requests it is best practise to process webhooks in a background queue and return a `200` to Shopify immediately. Ruby has several good background job frameworks that work with Sinatra including [Sidekiq](https://github.com/mperham/sidekiq) and [Resque](https://github.com/resque/resque).
109
109
 
110
- def self.perform(shop_name, shop_token, webhook_data)
111
- # do something with the data
112
- end
113
- end
114
- ```
115
110
 
116
111
  **after_shopify_auth** - This is a private method provided with the framework that gets called whenever the app is authorized. You should fill this method in with anything you need to initialize, for example webhooks and services on Shopify or any other database models you have created specific to a shop. Note that this method will be called anytime the auth flow is completed so this method should be idempotent (running it twice has the same effect as running it once).
117
112
 
@@ -129,7 +124,7 @@ shopify-sinatra-app includes sinatra/activerecord for creating models that can b
129
124
 
130
125
  shopify-sinatra-app also includes `rack-flash3` and the flash messages are forwarded to the Shopify Embedded App SDK (see the code in `views/layouts/application.erb`). Flash messages are useful for signaling to your users that a request was successful without changing the page. The following is an example of how to use a flash message in a route:
131
126
 
132
- ```
127
+ ```ruby
133
128
  post '/flash_message' do
134
129
  flash[:notice] = "Flash Message!"
135
130
  redirect '/'
@@ -146,7 +141,7 @@ The embedded app sdk won't load non https content so you'll need to use a forwar
146
141
  To run the app locally we use `foreman` which comes with the [Heroku Toolbelt](https://devcenter.heroku.com/articles/quickstart). Foreman handles running our application and setting our credentials as environment variables. To run the application type:
147
142
 
148
143
  ```
149
- foreman run bundle exec rackup config.ru
144
+ PORT=4567 foreman run web
150
145
  ```
151
146
 
152
147
  Note - we use `foreman run ...` not `foreman start ...` because we only want to start the single process that is our app. This means if you add a debugger in your app it will trigger properly in the command line when the debugger is hit. If you don't have any debuggers feel free to use `foreman start -p 4567`.
@@ -194,7 +189,6 @@ You will also need to add the following (free) add-ons to your new Heroku app:
194
189
 
195
190
  ```
196
191
  heroku addons:add heroku-postgresql
197
- heroku addons:add rediscloud
198
192
  ```
199
193
 
200
194
  Now we can deploy the new application to Heroku. Deploying to Heroku is as simple as pushing the code using git:
@@ -217,14 +211,12 @@ We also need to set our environment variables on Heroku. The environment variabl
217
211
  rake creds2heroku
218
212
  ```
219
213
 
220
- and make sure you have at least 1 dyno for web and resque:
214
+ and make sure you have at least 1 dyno for web:
221
215
 
222
216
  ```
223
- heroku scale web=1 resque=1
217
+ heroku scale web=1
224
218
  ```
225
219
 
226
- Note - if you are not using any background queue for processing webhooks then you do not need the redis add-on or the resque dyno so you can set it to 0.
227
-
228
220
  Make sure you set your shopify apps url to your Heroku app url (and make sure to use the `https` version or else the Embedded App SDK won't work) in the Shopify Partner area https://app.shopify.com/services/partners/api_clients.
229
221
 
230
222
 
data/example/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .env
2
2
  *.sqlite3
3
+ .byebug_history
data/example/Procfile CHANGED
@@ -1,2 +1 @@
1
1
  web: bundle exec rackup config.ru -p $PORT
2
- resque: env TERM_CHILD=1 RESQUE_TERM_TIMEOUT=7 QUEUE=default bundle exec rake resque:work
data/example/src/app.rb CHANGED
@@ -22,7 +22,7 @@ class SinatraApp < Sinatra::Base
22
22
  # stores more data.
23
23
  post '/uninstall' do
24
24
  webhook_session do |params|
25
- current_shop.destroy
25
+ Shop.find_by(name: current_shop_name).destroy
26
26
  end
27
27
  end
28
28
 
@@ -1,8 +1,6 @@
1
1
  require 'sinatra/base'
2
- require 'sinatra/redis'
3
2
  require 'sinatra/activerecord'
4
3
 
5
- require 'resque'
6
4
  require 'rack-flash'
7
5
  require 'attr_encrypted'
8
6
  require 'active_support/all'
@@ -58,25 +56,11 @@ module Sinatra
58
56
  redirect request.env['sinatra.route'].split(' ').last
59
57
  end
60
58
 
61
- def webhook_session(&blk)
59
+ def shopify_webhook(&blk)
62
60
  return unless verify_shopify_webhook
63
61
  @shop_name = request.env['HTTP_X_SHOPIFY_SHOP_DOMAIN']
64
- shop = Shop.find_by(name: @shop_name)
65
-
66
- if shop.present?
67
- params = ActiveSupport::JSON.decode(request.body.read.to_s)
68
- activate_shopify_api(shop.name, shop.token)
69
- yield params
70
- status 200
71
- end
72
- end
73
-
74
- def webhook_job(jobKlass)
75
- return unless verify_shopify_webhook
76
- @shop_name = request.env['HTTP_X_SHOPIFY_SHOP_DOMAIN']
77
- shop = Shop.find_by(name: @shop_name)
78
- params = ActiveSupport::JSON.decode(request.body.read.to_s)
79
- Resque.enqueue(jobKlass, shop.name, shop.token, params)
62
+ webhook_body = ActiveSupport::JSON.decode(request.body.read.to_s)
63
+ yield webhook_body
80
64
  status 200
81
65
  end
82
66
 
@@ -192,14 +176,6 @@ module Sinatra
192
176
  secret: app.settings.secret,
193
177
  expire_after: 60 * 30 # half an hour in seconds
194
178
 
195
- app.set :redis_url, ENV['REDISCLOUD_URL'] || 'redis://localhost:6379/'
196
- redis_uri = URI.parse(app.settings.redis_url)
197
- Resque.redis = ::Redis.new(host: redis_uri.host,
198
- port: redis_uri.port,
199
- password: redis_uri.password)
200
- Resque.redis.namespace = 'resque'
201
- app.set :redis, app.settings.redis_url
202
-
203
179
  app.use OmniAuth::Builder do
204
180
  provider :shopify,
205
181
  app.settings.api_key,
@@ -214,8 +190,10 @@ module Sinatra
214
190
  }
215
191
  end
216
192
 
217
- ShopifyAPI::Session.setup(api_key: app.settings.api_key,
218
- secret: app.settings.shared_secret)
193
+ ShopifyAPI::Session.setup(
194
+ api_key: app.settings.api_key,
195
+ secret: app.settings.shared_secret
196
+ )
219
197
 
220
198
  app.get '/install' do
221
199
  if params[:shop].present?
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'shopify-sinatra-app'
3
- s.version = '0.4.1'
3
+ s.version = '0.5.0'
4
4
 
5
5
  s.summary = 'A classy shopify app'
6
6
  s.description = 'A Sinatra extension for building Shopify Apps. Akin to the shopify_app gem but for Sinatra'
@@ -14,14 +14,11 @@ Gem::Specification.new do |s|
14
14
  s.executables << 'shopify-sinatra-app-generator'
15
15
 
16
16
  s.add_runtime_dependency 'sinatra', '~> 2.0.2'
17
- s.add_runtime_dependency 'sinatra-redis', '~> 0.3.0'
18
17
  s.add_runtime_dependency 'sinatra-activerecord', '~> 2.0.9'
19
18
  s.add_runtime_dependency 'rack-flash3', '~> 1.0.5'
20
19
  s.add_runtime_dependency 'activesupport'
21
20
  s.add_runtime_dependency 'attr_encrypted', '~> 3.1.0'
22
21
 
23
- s.add_runtime_dependency 'resque'
24
-
25
22
  s.add_runtime_dependency 'shopify_api'
26
23
  s.add_runtime_dependency 'omniauth-shopify-oauth2'
27
24
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify-sinatra-app
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Hughes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-24 00:00:00.000000000 Z
11
+ date: 2018-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.0.2
27
- - !ruby/object:Gem::Dependency
28
- name: sinatra-redis
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 0.3.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: 0.3.0
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: sinatra-activerecord
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +80,6 @@ dependencies:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
82
  version: 3.1.0
97
- - !ruby/object:Gem::Dependency
98
- name: resque
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
83
  - !ruby/object:Gem::Dependency
112
84
  name: shopify_api
113
85
  requirement: !ruby/object:Gem::Requirement
@@ -232,13 +204,11 @@ files:
232
204
  - ".travis.yml"
233
205
  - CHANGELOG
234
206
  - Gemfile
235
- - Gemfile.lock
236
207
  - LICENSE
237
208
  - README.md
238
209
  - bin/shopify-sinatra-app-generator
239
210
  - example/.gitignore
240
211
  - example/Gemfile
241
- - example/Gemfile.lock
242
212
  - example/Procfile
243
213
  - example/README.md
244
214
  - example/Rakefile
@@ -281,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
281
251
  version: '0'
282
252
  requirements: []
283
253
  rubyforge_project:
284
- rubygems_version: 2.7.3
254
+ rubygems_version: 2.7.6
285
255
  signing_key:
286
256
  specification_version: 4
287
257
  summary: A classy shopify app
data/Gemfile.lock DELETED
@@ -1,130 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- shopify-sinatra-app (0.4.0)
5
- activesupport
6
- attr_encrypted (~> 3.1.0)
7
- omniauth-shopify-oauth2
8
- rack-flash3 (~> 1.0.5)
9
- resque
10
- shopify_api
11
- sinatra (~> 2.0.2)
12
- sinatra-activerecord (~> 2.0.9)
13
- sinatra-redis (~> 0.3.0)
14
-
15
- GEM
16
- remote: https://rubygems.org/
17
- specs:
18
- activemodel (5.2.0)
19
- activesupport (= 5.2.0)
20
- activemodel-serializers-xml (1.0.2)
21
- activemodel (> 5.x)
22
- activesupport (> 5.x)
23
- builder (~> 3.1)
24
- activerecord (5.2.0)
25
- activemodel (= 5.2.0)
26
- activesupport (= 5.2.0)
27
- arel (>= 9.0)
28
- activeresource (5.0.0)
29
- activemodel (>= 5.0, < 6)
30
- activemodel-serializers-xml (~> 1.0)
31
- activesupport (>= 5.0, < 6)
32
- activesupport (5.2.0)
33
- concurrent-ruby (~> 1.0, >= 1.0.2)
34
- i18n (>= 0.7, < 2)
35
- minitest (~> 5.1)
36
- tzinfo (~> 1.1)
37
- arel (9.0.0)
38
- attr_encrypted (3.1.0)
39
- encryptor (~> 3.0.0)
40
- builder (3.2.3)
41
- concurrent-ruby (1.0.5)
42
- encryptor (3.0.0)
43
- fakeweb (1.3.0)
44
- faraday (0.12.2)
45
- multipart-post (>= 1.2, < 3)
46
- graphql (1.8.5)
47
- graphql-client (0.13.0)
48
- activesupport (>= 3.0, < 6.0)
49
- graphql (~> 1.6)
50
- hashie (3.5.7)
51
- i18n (1.0.1)
52
- concurrent-ruby (~> 1.0)
53
- jwt (1.5.6)
54
- metaclass (0.0.4)
55
- minitest (5.11.3)
56
- mocha (1.3.0)
57
- metaclass (~> 0.0.1)
58
- mono_logger (1.1.0)
59
- multi_json (1.13.1)
60
- multi_xml (0.6.0)
61
- multipart-post (2.0.0)
62
- mustermann (1.0.2)
63
- oauth2 (1.4.0)
64
- faraday (>= 0.8, < 0.13)
65
- jwt (~> 1.0)
66
- multi_json (~> 1.3)
67
- multi_xml (~> 0.5)
68
- rack (>= 1.2, < 3)
69
- omniauth (1.8.1)
70
- hashie (>= 3.4.6, < 3.6.0)
71
- rack (>= 1.6.2, < 3)
72
- omniauth-oauth2 (1.5.0)
73
- oauth2 (~> 1.1)
74
- omniauth (~> 1.2)
75
- omniauth-shopify-oauth2 (1.2.1)
76
- omniauth-oauth2 (~> 1.5.0)
77
- rack (2.0.4)
78
- rack-flash3 (1.0.5)
79
- rack
80
- rack-protection (2.0.3)
81
- rack
82
- rack-test (0.8.3)
83
- rack (>= 1.0, < 3)
84
- rake (12.3.0)
85
- redis (4.0.1)
86
- redis-namespace (1.6.0)
87
- redis (>= 3.0.4)
88
- resque (1.27.4)
89
- mono_logger (~> 1.0)
90
- multi_json (~> 1.0)
91
- redis-namespace (~> 1.3)
92
- sinatra (>= 0.9.2)
93
- vegas (~> 0.1.2)
94
- shopify_api (4.12.0)
95
- activeresource (>= 3.0.0)
96
- graphql-client
97
- rack
98
- sinatra (2.0.3)
99
- mustermann (~> 1.0)
100
- rack (~> 2.0)
101
- rack-protection (= 2.0.3)
102
- tilt (~> 2.0)
103
- sinatra-activerecord (2.0.13)
104
- activerecord (>= 3.2)
105
- sinatra (>= 1.0)
106
- sinatra-redis (0.3.0)
107
- redis
108
- sinatra (>= 0.9.4)
109
- sqlite3 (1.3.13)
110
- thread_safe (0.3.6)
111
- tilt (2.0.8)
112
- tzinfo (1.2.5)
113
- thread_safe (~> 0.1)
114
- vegas (0.1.11)
115
- rack (>= 1.0.0)
116
-
117
- PLATFORMS
118
- ruby
119
-
120
- DEPENDENCIES
121
- fakeweb
122
- minitest
123
- mocha
124
- rack-test
125
- rake
126
- shopify-sinatra-app!
127
- sqlite3
128
-
129
- BUNDLED WITH
130
- 1.16.3
data/example/Gemfile.lock DELETED
@@ -1,145 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- shopify-sinatra-app (0.4.0)
5
- activesupport
6
- attr_encrypted (~> 3.1.0)
7
- omniauth-shopify-oauth2
8
- rack-flash3 (~> 1.0.5)
9
- resque
10
- shopify_api
11
- sinatra (~> 2.0.2)
12
- sinatra-activerecord (~> 2.0.9)
13
- sinatra-redis (~> 0.3.0)
14
-
15
- GEM
16
- remote: https://rubygems.org/
17
- specs:
18
- activemodel (5.1.5)
19
- activesupport (= 5.1.5)
20
- activemodel-serializers-xml (1.0.2)
21
- activemodel (> 5.x)
22
- activesupport (> 5.x)
23
- builder (~> 3.1)
24
- activerecord (5.1.5)
25
- activemodel (= 5.1.5)
26
- activesupport (= 5.1.5)
27
- arel (~> 8.0)
28
- activeresource (5.0.0)
29
- activemodel (>= 5.0, < 6)
30
- activemodel-serializers-xml (~> 1.0)
31
- activesupport (>= 5.0, < 6)
32
- activesupport (5.1.5)
33
- concurrent-ruby (~> 1.0, >= 1.0.2)
34
- i18n (~> 0.7)
35
- minitest (~> 5.1)
36
- tzinfo (~> 1.1)
37
- arel (8.0.0)
38
- attr_encrypted (3.1.0)
39
- encryptor (~> 3.0.0)
40
- builder (3.2.3)
41
- byebug (10.0.0)
42
- concurrent-ruby (1.0.5)
43
- dotenv (2.2.1)
44
- encryptor (3.0.0)
45
- fakeweb (1.3.0)
46
- faraday (0.12.2)
47
- multipart-post (>= 1.2, < 3)
48
- foreman (0.84.0)
49
- thor (~> 0.19.1)
50
- graphql (1.8.5)
51
- graphql-client (0.13.0)
52
- activesupport (>= 3.0, < 6.0)
53
- graphql (~> 1.6)
54
- hashie (3.5.7)
55
- i18n (0.9.5)
56
- concurrent-ruby (~> 1.0)
57
- jwt (1.5.6)
58
- metaclass (0.0.4)
59
- minitest (5.11.3)
60
- mocha (1.3.0)
61
- metaclass (~> 0.0.1)
62
- mono_logger (1.1.0)
63
- multi_json (1.13.1)
64
- multi_xml (0.6.0)
65
- multipart-post (2.0.0)
66
- mustermann (1.0.2)
67
- oauth2 (1.4.0)
68
- faraday (>= 0.8, < 0.13)
69
- jwt (~> 1.0)
70
- multi_json (~> 1.3)
71
- multi_xml (~> 0.5)
72
- rack (>= 1.2, < 3)
73
- omniauth (1.8.1)
74
- hashie (>= 3.4.6, < 3.6.0)
75
- rack (>= 1.6.2, < 3)
76
- omniauth-oauth2 (1.5.0)
77
- oauth2 (~> 1.1)
78
- omniauth (~> 1.2)
79
- omniauth-shopify-oauth2 (1.2.1)
80
- omniauth-oauth2 (~> 1.5.0)
81
- pg (1.0.0)
82
- rack (2.0.5)
83
- rack-flash3 (1.0.5)
84
- rack
85
- rack-protection (2.0.3)
86
- rack
87
- rack-test (0.8.3)
88
- rack (>= 1.0, < 3)
89
- rake (12.3.0)
90
- redis (4.0.1)
91
- redis-namespace (1.6.0)
92
- redis (>= 3.0.4)
93
- resque (1.27.4)
94
- mono_logger (~> 1.0)
95
- multi_json (~> 1.0)
96
- redis-namespace (~> 1.3)
97
- sinatra (>= 0.9.2)
98
- vegas (~> 0.1.2)
99
- shopify_api (4.12.0)
100
- activeresource (>= 3.0.0)
101
- graphql-client
102
- rack
103
- sinatra (2.0.3)
104
- mustermann (~> 1.0)
105
- rack (~> 2.0)
106
- rack-protection (= 2.0.3)
107
- tilt (~> 2.0)
108
- sinatra-activerecord (2.0.13)
109
- activerecord (>= 3.2)
110
- sinatra (>= 1.0)
111
- sinatra-redis (0.3.0)
112
- redis
113
- sinatra (>= 0.9.4)
114
- sqlite3 (1.3.13)
115
- thor (0.19.4)
116
- thread_safe (0.3.6)
117
- tilt (2.0.8)
118
- tzinfo (1.2.5)
119
- thread_safe (~> 0.1)
120
- vegas (0.1.11)
121
- rack (>= 1.0.0)
122
-
123
- PLATFORMS
124
- ruby
125
-
126
- DEPENDENCIES
127
- byebug
128
- dotenv
129
- fakeweb
130
- foreman
131
- minitest
132
- mocha
133
- pg
134
- rack-flash3
135
- rack-test
136
- rake
137
- shopify-sinatra-app!
138
- sinatra-activerecord
139
- sqlite3
140
-
141
- RUBY VERSION
142
- ruby 2.5.0p0
143
-
144
- BUNDLED WITH
145
- 1.16.1