hoboken 0.0.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +7 -0
  3. data/.github/workflows/ruby.yml +28 -0
  4. data/.rubocop.yml +33 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +2 -0
  7. data/IDEAS.md +57 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +21 -10
  10. data/Rakefile +14 -6
  11. data/bin/hoboken +2 -1
  12. data/hoboken.gemspec +53 -16
  13. data/lib/hoboken.rb +110 -23
  14. data/lib/hoboken/actions.rb +10 -6
  15. data/lib/hoboken/add_ons/github_action.rb +14 -0
  16. data/lib/hoboken/add_ons/heroku.rb +8 -23
  17. data/lib/hoboken/add_ons/internationalization.rb +10 -6
  18. data/lib/hoboken/add_ons/metrics.rb +39 -14
  19. data/lib/hoboken/add_ons/omniauth.rb +114 -47
  20. data/lib/hoboken/add_ons/rubocop.rb +40 -0
  21. data/lib/hoboken/add_ons/sequel.rb +76 -47
  22. data/lib/hoboken/add_ons/sprockets.rb +67 -65
  23. data/lib/hoboken/add_ons/travis.rb +6 -2
  24. data/lib/hoboken/add_ons/twbs.rb +80 -0
  25. data/lib/hoboken/generate.rb +112 -38
  26. data/lib/hoboken/templates/Gemfile.erb.tt +33 -10
  27. data/lib/hoboken/templates/README.md.tt +105 -35
  28. data/lib/hoboken/templates/Rakefile.tt +10 -22
  29. data/lib/hoboken/templates/classic.rb.tt +35 -8
  30. data/lib/hoboken/templates/config.ru.tt +5 -3
  31. data/lib/hoboken/templates/console.sh +5 -0
  32. data/lib/hoboken/templates/db.rb.tt +24 -0
  33. data/lib/hoboken/templates/github_action.tt +28 -0
  34. data/lib/hoboken/templates/gitignore +8 -1
  35. data/lib/hoboken/templates/metrics.rake.tt +10 -9
  36. data/lib/hoboken/templates/modular.rb.tt +40 -11
  37. data/lib/hoboken/templates/puma.rb.tt +21 -0
  38. data/lib/hoboken/templates/rspec.rake.tt +5 -0
  39. data/lib/hoboken/templates/rubocop.yml.tt +31 -0
  40. data/lib/hoboken/templates/sequel.rake +6 -4
  41. data/lib/hoboken/templates/server.sh +12 -0
  42. data/lib/hoboken/templates/setup.sh +7 -0
  43. data/lib/hoboken/templates/spec/app_spec.rb.tt +15 -0
  44. data/lib/hoboken/templates/spec/rack_matchers.rb.tt +56 -0
  45. data/lib/hoboken/templates/spec/spec_helper.rb.tt +41 -0
  46. data/lib/hoboken/templates/sprockets.rake +13 -7
  47. data/lib/hoboken/templates/sprockets_chain.rb +7 -3
  48. data/lib/hoboken/templates/sprockets_helper.rb +14 -10
  49. data/lib/hoboken/templates/support/rack_helpers.rb.tt +55 -0
  50. data/lib/hoboken/templates/support/rack_test_assertions.rb.tt +111 -0
  51. data/lib/hoboken/templates/test/test_helper.rb.tt +38 -27
  52. data/lib/hoboken/templates/test/unit/app_test.rb.tt +11 -3
  53. data/lib/hoboken/templates/test_unit.rake.tt +18 -0
  54. data/lib/hoboken/templates/views/index.erb.tt +10 -3
  55. data/lib/hoboken/templates/views/layout.erb.tt +4 -1
  56. data/lib/hoboken/version.rb +3 -1
  57. data/test/fixtures/Gemfile +3 -3
  58. data/test/fixtures/Gemfile.pristine +3 -2
  59. data/test/integration/add_on_test.rb +399 -136
  60. data/test/integration/generate_test.rb +170 -38
  61. data/test/test_helper.rb +54 -23
  62. data/test/unit/hoboken_actions_test.rb +70 -61
  63. metadata +441 -16
  64. data/.travis.yml +0 -5
  65. data/lib/hoboken/templates/test/support/rack_test_assertions.rb.tt +0 -92
@@ -1,17 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hoboken
4
+ # Custom actions.
5
+ #
2
6
  module Actions
3
7
  def gem(name, opts={})
4
- verbose = opts.has_key?(:verbose) ? opts.delete(:verbose) : true
5
- version = opts.has_key?(:version) ? opts.delete(:version) : nil
8
+ verbose = opts.key?(:verbose) ? opts.delete(:verbose) : true
9
+ version = opts.key?(:version) ? opts.delete(:version) : nil
6
10
 
7
- parts = [name.inspect]
8
- parts << "~> #{version}".inspect unless version.nil? || version.empty?
11
+ parts = ["'#{name}'"]
12
+ parts << "'~> #{version}'" unless version.nil? || version.empty?
9
13
  opts.each { |k, v| parts << "#{k}: #{v.inspect}" }
10
- append_file("Gemfile", "\ngem #{parts.join(", ")}", verbose: verbose)
14
+ append_file('Gemfile', "gem #{parts.join(', ')}\n", verbose: verbose)
11
15
  end
12
16
 
13
17
  def indent(text, num_spaces)
14
- text.gsub(/^/, 1.upto(num_spaces).map { |n| " " }.join)
18
+ text.gsub(/^/, 1.upto(num_spaces).map { |_| ' ' }.join)
15
19
  end
16
20
  end
17
21
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hoboken
4
+ module AddOns
5
+ # Github action that runs CI task.
6
+ #
7
+ class GithubAction < ::Hoboken::Group
8
+ def add_action_yml_file
9
+ empty_directory('.github/workflows')
10
+ template('hoboken/templates/github_action.tt', '.github/workflows/ruby.yml')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,34 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hoboken
2
4
  module AddOns
5
+ # Heroku deployment support.
6
+ #
3
7
  class Heroku < ::Hoboken::Group
4
- def add_gem
5
- gem "foreman", version: "0.63.0", group: :development
6
- end
7
-
8
- def procfile
9
- create_file("Procfile") do
10
- "web: bundle exec thin start -p $PORT -e $RACK_ENV"
11
- end
12
- end
13
-
14
8
  def slugignore
15
- create_file(".slugignore") do
16
- "tags\n/test\n/tmp"
9
+ create_file('.slugignore') do
10
+ "spec\ntags\n/test\n/tmp"
17
11
  end
18
12
  end
19
13
 
20
14
  def fix_stdout_for_logging
21
- prepend_file("config.ru", "$stdout.sync = true\n")
22
- end
23
-
24
- def replace_server_rake_task
25
- gsub_file("Rakefile", /desc.*server.*{rack_env}"\)\nend$/m) do
26
- <<TASK
27
- desc "Start the development server with Foreman"
28
- task :server do
29
- exec("foreman start")
30
- end
31
- TASK
15
+ insert_into_file('config.ru', after: /# frozen_string_literal: true/) do
16
+ "\n\n$stdout.sync = true"
32
17
  end
33
18
  end
34
19
 
@@ -1,19 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hoboken
2
4
  module AddOns
5
+ # Internationalization support using sinatra-r18n.
6
+ #
3
7
  class Internationalization < ::Hoboken::Group
4
8
  def add_gem
5
- gem "sinatra-r18n", version: "1.1.5"
6
- insert_into_file("app.rb", after: /require "sinatra("|\/base")/) do
7
- "\nrequire \"sinatra/r18n\""
9
+ gem 'sinatra-r18n', version: '5.0'
10
+ insert_into_file('app.rb', after: %r{require 'sinatra('|/base')}) do
11
+ "\nrequire 'sinatra/r18n'"
8
12
  end
9
- insert_into_file("app.rb", after: /Sinatra::Base/) do
13
+ insert_into_file('app.rb', after: /Sinatra::Base/) do
10
14
  "\n register Sinatra::R18n"
11
15
  end
12
16
  end
13
17
 
14
18
  def translations
15
- empty_directory("i18n")
16
- template("hoboken/templates/en.yml.tt", "i18n/en.yml")
19
+ empty_directory('i18n')
20
+ template('hoboken/templates/en.yml.tt', 'i18n/en.yml')
17
21
  end
18
22
 
19
23
  def reminders
@@ -1,34 +1,59 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hoboken
2
4
  module AddOns
5
+ # Add metrics (flog, flay, simplecov).
6
+ #
3
7
  class Metrics < ::Hoboken::Group
4
8
  def add_gems
5
- gem "flog", version: "2.5.3", group: :test
6
- gem "flay", version: "1.4.3", group: :test
7
- gem "simplecov", version: "0.7.1", require: false, group: :test
9
+ gem 'flog', version: '4.6', group: :test
10
+ gem 'flay', version: '2.12', group: :test
11
+ gem 'simplecov', version: '0.21', require: false, group: :test
8
12
  end
9
13
 
10
14
  def copy_task_templates
11
- empty_directory("tasks")
12
- template("hoboken/templates/metrics.rake.tt", "tasks/metrics.rake")
15
+ empty_directory('tasks')
16
+ template('hoboken/templates/metrics.rake.tt', 'tasks/metrics.rake')
13
17
  end
14
18
 
15
- def simplecov_snippet
16
- insert_into_file "test/test_helper.rb", before: /require "test\/unit"/ do
17
- <<CODE
19
+ def simplecov_test_unit
20
+ return if rspec?
18
21
 
19
- require 'simplecov'
20
- SimpleCov.start do
21
- add_filter "/test/"
22
- coverage_dir 'tmp/coverage'
23
- end
22
+ insert_into_file 'test/test_helper.rb', before: snippet_location do
23
+ snippet('test')
24
+ end
25
+ end
26
+
27
+ def simplecov_rspec
28
+ return unless rspec?
24
29
 
25
- CODE
30
+ insert_into_file 'spec/spec_helper.rb', before: snippet_location do
31
+ snippet('rspec')
26
32
  end
27
33
  end
28
34
 
29
35
  def reminders
30
36
  say "\nGemfile updated... don't forget to 'bundle install'"
31
37
  end
38
+
39
+ private
40
+
41
+ def snippet(framework_folder)
42
+ <<~CODE
43
+ require 'simplecov'
44
+ SimpleCov.start do
45
+ add_filter '/bin/'
46
+ add_filter '/config/'
47
+ add_filter '/#{framework_folder}/'
48
+ coverage_dir 'tmp/coverage'
49
+ end
50
+
51
+ CODE
52
+ end
53
+
54
+ def snippet_location
55
+ %r{require 'bundler/setup'}
56
+ end
32
57
  end
33
58
  end
34
59
  end
@@ -1,92 +1,163 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hoboken
2
4
  module AddOns
5
+ # OmniAuth authentication (allows you to select a provider).
6
+ #
3
7
  class OmniAuth < ::Hoboken::Group
4
8
  attr_reader :provider
5
9
 
6
10
  def add_gem
7
- @provider = ask("Specify a provider (i.e. twitter, facebook. etc.): ").downcase
8
- provider_version = ask("Specify provider version: ")
11
+ @provider = ask('Specify a provider (i.e. twitter, facebook. etc.): ').downcase
12
+ provider_version = ask('Specify provider version: ')
9
13
  gem gem_name, version: provider_version
10
14
  end
11
15
 
12
16
  def setup_middleware
13
- insert_into_file("app.rb", after: /require "sinatra("|\/base")/) do
14
- "\nrequire \"#{gem_name}\""
17
+ insert_into_file('app.rb', after: %r{require 'sinatra('|/base')}) do
18
+ "\nrequire '#{gem_name}'\nrequire 'sinatra/json'\n"
15
19
  end
16
20
 
17
- snippet = <<-CODE
18
-
19
- use OmniAuth::Builder do
20
- provider :#{provider}, ENV["#{provider.upcase}_KEY"], ENV["#{provider.upcase}_SECRET"]
21
- end
22
-
23
- CODE
21
+ snippet = <<~CODE
22
+ use OmniAuth::Builder do
23
+ provider :#{provider}, ENV['#{provider.upcase}_KEY'], ENV['#{provider.upcase}_SECRET']
24
+ end
25
+ CODE
24
26
 
25
- text = modular? ? indent(snippet, 4) : snippet
26
- insert_into_file("app.rb", after: /use Rack::Session::Cookie.+\n/) { text }
27
+ indentation = classic? ? 2 : 4
28
+ insert_into_file('app.rb', after: /use Rack::Session::Cookie.+\n/) do
29
+ "\n#{indent(snippet, indentation)}\n"
30
+ end
27
31
  end
28
32
 
33
+ # rubocop:disable Metrics/MethodLength
29
34
  def add_routes
30
- routes = <<-CODE
31
-
35
+ routes = <<~CODE
32
36
 
33
- get "/login" do
34
- '<a href="/auth/#{provider}">Login</a>'
35
- end
37
+ get '/login' do
38
+ '<a href="/auth/#{provider}">Login</a>'
39
+ end
36
40
 
37
- get "/auth/:provider/callback" do
38
- # TODO: Insert real authentication logic...
39
- MultiJson.encode(request.env['omniauth.auth'])
40
- end
41
+ get '/auth/:provider/callback' do
42
+ # TODO: Insert real authentication logic...
43
+ json request.env['omniauth.auth']
44
+ end
41
45
 
42
- get "/auth/failure" do
43
- # TODO: Insert real error handling logic...
44
- halt 401, params[:message]
45
- end
46
- CODE
46
+ get '/auth/failure' do
47
+ # TODO: Insert real error handling logic...
48
+ halt 401, params[:message]
49
+ end
50
+ CODE
47
51
 
48
- if modular?
49
- insert_into_file("app.rb", after: /get.+?end$/m) { indent(routes, 4) }
52
+ if classic?
53
+ append_file('app.rb', routes)
50
54
  else
51
- append_file("app.rb", routes)
55
+ inject_into_class('app.rb', 'App') { indent(routes, 4) }
52
56
  end
53
57
  end
58
+ # rubocop:enable Metrics/MethodLength
54
59
 
60
+ # rubocop:disable Metrics/MethodLength
55
61
  def add_tests
56
- inject_into_class("test/unit/app_test.rb", "AppTest") do
57
- <<-CODE
62
+ return if rspec?
63
+
64
+ inject_into_class('test/unit/app_test.rb', 'AppTest') do
65
+ <<-CODE
58
66
  setup do
59
67
  OmniAuth.config.test_mode = true
60
68
  end
61
69
 
62
- test "GET /login" do
63
- get "/login"
70
+ test 'GET /login' do
71
+ get '/login'
64
72
  assert_equal('<a href="/auth/#{provider}">Login</a>', last_response.body)
65
73
  end
66
74
 
67
- test "GET /auth/#{provider}/callback" do
75
+ test 'GET /auth/#{provider}/callback' do
68
76
  auth_hash = {
69
- "provider" => "#{provider}",
70
- "uid" => "123545",
71
- "info" => {
72
- "name" => "John Doe"
77
+ provider: '#{provider}',
78
+ uid: '123545',
79
+ info: {
80
+ name: 'John Doe'
73
81
  }
74
82
  }
75
83
 
76
84
  OmniAuth.config.mock_auth[:#{provider}] = auth_hash
77
- get "/auth/fitbit/callback"
85
+ get '/auth/#{provider}/callback'
78
86
  assert_equal(MultiJson.encode(auth_hash), last_response.body)
79
87
  end
80
88
 
81
- test "GET /auth/failure" do
89
+ test 'GET /auth/failure' do
82
90
  OmniAuth.config.mock_auth[:#{provider}] = :invalid_credentials
83
- get "/auth/failure"
91
+ get '/auth/failure'
84
92
  assert_response :not_authorized
85
93
  end
86
94
 
87
- CODE
95
+ CODE
88
96
  end
89
97
  end
98
+ # rubocop:enable Metrics/MethodLength
99
+
100
+ # rubocop:disable Metrics/MethodLength
101
+ def add_specs
102
+ return unless rspec?
103
+
104
+ append_file('spec/app_spec.rb') do
105
+ <<~CODE
106
+
107
+ # rubocop:disable RSpec/DescribeClass
108
+ RSpec.describe 'omniauth', rack: true do
109
+ before(:each) { OmniAuth.config.test_mode = true }
110
+
111
+ describe 'GET /login' do
112
+ before(:each) { get '/login' }
113
+
114
+ it { expect(last_response).to have_http_status(:ok) }
115
+ it { expect(last_response).to have_content_type(:html) }
116
+
117
+ it 'renders a template with a login link' do
118
+ #{provider}_link = '<a href="/auth/#{provider}">Login</a>'
119
+ expect(last_response.body).to include(#{provider}_link)
120
+ end
121
+ end
122
+
123
+ describe 'GET /auth/#{provider}/callback' do
124
+ let(:auth_hash) do
125
+ {
126
+ provider: '#{provider}',
127
+ uid: '123545',
128
+ info: {
129
+ name: 'John Doe'
130
+ }
131
+ }
132
+ end
133
+
134
+ before(:each) do
135
+ OmniAuth.config.mock_auth[:#{provider}] = auth_hash
136
+ get '/auth/#{provider}/callback'
137
+ end
138
+
139
+ it { expect(last_response).to have_http_status(:ok) }
140
+ it { expect(last_response).to have_content_type(:json) }
141
+
142
+ it 'renders the auth hash result' do
143
+ expect(last_response.body).to eq(JSON.generate(auth_hash))
144
+ end
145
+ end
146
+
147
+ describe 'GET /auth/failure' do
148
+ before(:each) do
149
+ OmniAuth.config.mock_auth[:#{provider}] = :invalid_credentials
150
+ get '/auth/failure'
151
+ end
152
+
153
+ it { expect(last_response).to have_http_status(:not_authorized) }
154
+ end
155
+ end
156
+ # rubocop:enable RSpec/DescribeClass
157
+ CODE
158
+ end
159
+ end
160
+ # rubocop:enable Metrics/MethodLength
90
161
 
91
162
  def reminders
92
163
  say "\nGemfile updated... don't forget to 'bundle install'"
@@ -97,10 +168,6 @@ CODE
97
168
  def gem_name
98
169
  "omniauth-#{provider}"
99
170
  end
100
-
101
- def modular?
102
- @modular ||= File.readlines("app.rb").grep(/Sinatra::Base/).any?
103
- end
104
171
  end
105
172
  end
106
173
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hoboken
4
+ module AddOns
5
+ # Basic Rubocop YAML config.
6
+ #
7
+ class Rubocop < ::Hoboken::Group
8
+ def add_gems
9
+ gem 'rubocop', version: '1.12', group: %i[development test]
10
+ gem 'rubocop-rake', version: '0.5', group: %i[development test]
11
+ gem 'rubocop-rspec', version: '2.2', group: %i[development test] if rspec?
12
+ end
13
+
14
+ def rubocop_yml
15
+ template('hoboken/templates/rubocop.yml.tt', '.rubocop.yml')
16
+ end
17
+
18
+ def rake_task
19
+ create_file('tasks/rubocop.rake') do
20
+ <<~TEXT
21
+ # frozen_string_literal: true
22
+
23
+ require 'rubocop/rake_task'
24
+
25
+ RuboCop::RakeTask.new
26
+ TEXT
27
+ end
28
+ end
29
+
30
+ def ci_task
31
+ task_list = if rspec?
32
+ '%w[rspec rubocop]'
33
+ else
34
+ "['test:all', 'rubocop']"
35
+ end
36
+ gsub_file('Rakefile', /task ci:.*/, "task ci: #{task_list}")
37
+ end
38
+ end
39
+ end
40
+ end