hoboken 0.0.1 → 0.9.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.
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