grape-starter 0.2.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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rubocop.yml +36 -0
  4. data/.rubocop_todo.yml +12 -0
  5. data/.travis.yml +5 -0
  6. data/CHANGELOG.md +27 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +21 -0
  9. data/README.md +70 -0
  10. data/Rakefile +14 -0
  11. data/bin/grape-starter +119 -0
  12. data/grape-starter.gemspec +36 -0
  13. data/lib/starter.rb +9 -0
  14. data/lib/starter/builder.rb +90 -0
  15. data/lib/starter/builder/names.rb +56 -0
  16. data/lib/starter/builder/template_endpoints.rb +97 -0
  17. data/lib/starter/builder/template_files.rb +73 -0
  18. data/lib/starter/rake/grape_tasks.rb +71 -0
  19. data/lib/starter/rspec/request_specs.rb +109 -0
  20. data/lib/starter/version.rb +4 -0
  21. data/template/.rubocop.yml +15 -0
  22. data/template/.rubocop_todo.yml +28 -0
  23. data/template/Gemfile +23 -0
  24. data/template/LICENSE +21 -0
  25. data/template/README.md +70 -0
  26. data/template/Rakefile +25 -0
  27. data/template/api/base.rb +18 -0
  28. data/template/api/endpoints/root.rb +20 -0
  29. data/template/api/entities/api_error.rb +17 -0
  30. data/template/api/entities/route.rb +22 -0
  31. data/template/config.ru +12 -0
  32. data/template/config/application.rb +22 -0
  33. data/template/config/boot.rb +3 -0
  34. data/template/config/environment.rb +4 -0
  35. data/template/lib/api.rb +6 -0
  36. data/template/lib/api/version.rb +4 -0
  37. data/template/script/console +8 -0
  38. data/template/script/server +14 -0
  39. data/template/script/setup +6 -0
  40. data/template/script/stop +8 -0
  41. data/template/script/test +17 -0
  42. data/template/script/update +6 -0
  43. data/template/spec/lib/api/version_spec.rb +8 -0
  44. data/template/spec/requests/documentation_spec.rb +12 -0
  45. data/template/spec/requests/root_spec.rb +25 -0
  46. data/template/spec/spec_helper.rb +25 -0
  47. metadata +216 -0
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ module Starter
3
+ module Names
4
+ def klass_name
5
+ for_klass = prepare_klass
6
+ singular? ? for_klass.classify : for_klass.classify.pluralize
7
+ end
8
+
9
+ def base_file_name
10
+ @resource.tr('/', '-').downcase + '.rb'
11
+ end
12
+
13
+ def base_spec_name
14
+ base_file_name.gsub(/.rb$/, '_spec.rb')
15
+ end
16
+
17
+ def api_base_file_name
18
+ File.join(Dir.getwd, 'api', 'base.rb')
19
+ end
20
+
21
+ # resource file
22
+ def api_file_name
23
+ File.join(Dir.getwd, 'api', 'endpoints', base_file_name)
24
+ end
25
+
26
+ # resource file
27
+ def entity_file_name
28
+ File.join(Dir.getwd, 'api', 'entities', base_file_name)
29
+ end
30
+
31
+ # lib file
32
+ def lib_file_name
33
+ File.join(Dir.getwd, 'lib', 'api', base_file_name)
34
+ end
35
+
36
+ # resource spec
37
+ def api_spec_name
38
+ File.join(Dir.getwd, 'spec', 'requests', base_spec_name)
39
+ end
40
+
41
+ # lib spec
42
+ def lib_spec_name
43
+ File.join(Dir.getwd, 'spec', 'lib', 'api', base_spec_name)
44
+ end
45
+
46
+ private
47
+
48
+ def prepare_klass
49
+ @resource.tr('-', '/')
50
+ end
51
+
52
+ def singular?
53
+ @resource.singularize.inspect == @resource.inspect
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ module Starter
3
+ module Template
4
+ # defining the endpoints -> http methods of a resource
5
+ module Endpoints
6
+ def crud
7
+ %i(
8
+ post
9
+ get_all
10
+ get_specific
11
+ put_specific
12
+ patch_specific
13
+ delete_specific
14
+ )
15
+ end
16
+
17
+ def singular_one
18
+ %i(
19
+ post
20
+ get_one
21
+ put_one
22
+ patch_one
23
+ delete_one
24
+ )
25
+ end
26
+
27
+ # available API/HTTP methods
28
+ # POST
29
+ def post
30
+ "
31
+ desc 'create #{resource.singularize}'
32
+ params do
33
+ # TODO: specify the parameters
34
+ end
35
+ post do
36
+ # your code goes here
37
+ end"
38
+ end
39
+
40
+ # GET
41
+ def get_all
42
+ "
43
+ desc 'get all of #{resource.pluralize}',
44
+ is_array: true
45
+ get do
46
+ # your code goes here
47
+ end"
48
+ end
49
+
50
+ %w(get put patch delete).each do |verb|
51
+ define_method(:"#{verb}_one") do
52
+ "
53
+ desc '#{verb} #{resource.singularize}'
54
+ #{verb} do
55
+ # your code goes here
56
+ end"
57
+ end
58
+ end
59
+
60
+ %w(get put patch delete).each do |verb|
61
+ define_method(:"#{verb}_specific") do
62
+ "
63
+ desc '#{verb} specific #{resource.singularize}'
64
+ params do
65
+ requires :id
66
+ end
67
+ #{verb} ':id' do
68
+ # your code goes here
69
+ present :params, params
70
+ end"
71
+ end
72
+ end
73
+
74
+ # request specs shared examples
75
+ #
76
+ def post_spec
77
+ "it_behaves_like 'POST', base_path: '/api/v1', resource: '#{resource}'"
78
+ end
79
+
80
+ def get_all_spec
81
+ "it_behaves_like 'GET all', base_path: '/api/v1', resource: '#{resource}'"
82
+ end
83
+
84
+ %w(get put patch delete).each do |verb|
85
+ define_method(:"#{verb}_one_spec") do
86
+ "it_behaves_like '#{verb.upcase} one', base_path: '/api/v1', resource: '#{resource}'"
87
+ end
88
+ end
89
+
90
+ %w(get put patch delete).each do |verb|
91
+ define_method(:"#{verb}_specific_spec") do
92
+ "it_behaves_like '#{verb.upcase} specific', base_path: '/api/v1', resource: '#{resource}', key: 1"
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ require 'active_support/core_ext/string'
3
+
4
+ module Starter
5
+ module Template
6
+ module Files
7
+ # API template for resource
8
+ def api_file
9
+ <<-FILE.strip_heredoc
10
+ # frozen_string_literal: true
11
+
12
+ module Api
13
+ module Endpoints
14
+ class #{klass_name} < Grape::API
15
+ namespace :#{resource.downcase} do
16
+ #{endpoints}
17
+ end
18
+ end
19
+ end
20
+ end
21
+ FILE
22
+ end
23
+
24
+ def entity_file
25
+ <<-FILE.strip_heredoc
26
+ # frozen_string_literal: true
27
+
28
+ module Api
29
+ module Entities
30
+ class #{klass_name} < Grape::Entity
31
+ end
32
+ end
33
+ end
34
+ FILE
35
+ end
36
+
37
+ # LIB template for resource
38
+ def lib_file
39
+ <<-FILE.strip_heredoc
40
+ # frozen_string_literal: true
41
+
42
+ module Api
43
+ class #{klass_name}
44
+ end
45
+ end
46
+ FILE
47
+ end
48
+
49
+ def api_spec
50
+ <<-FILE.strip_heredoc
51
+ # frozen_string_literal: true
52
+ require 'spec_helper'
53
+
54
+ RSpec.describe Api::#{klass_name} do
55
+ pending 'write specs'
56
+ #{endpoint_specs}
57
+ end
58
+ FILE
59
+ end
60
+
61
+ def lib_spec
62
+ <<-FILE.strip_heredoc
63
+ # frozen_string_literal: true
64
+ require 'spec_helper'
65
+
66
+ RSpec.describe Api::#{klass_name} do
67
+ pending 'write specs'
68
+ end
69
+ FILE
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+ require 'rack/test'
5
+
6
+ module Starter
7
+ module Rake
8
+ require 'starter/builder'
9
+
10
+ class GrapeTasks < ::Rake::TaskLib
11
+ include Rack::Test::Methods
12
+
13
+ attr_reader :resource
14
+ attr_reader :api_class
15
+
16
+ def initialize(api_class = nil)
17
+ super()
18
+
19
+ @api_class = api_class
20
+ define_tasks
21
+ end
22
+
23
+ def api_routes
24
+ api_class.routes.each_with_object([]) do |route, memo|
25
+ memo << { verb: route.request_method, path: build_path(route), description: route.description }
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def define_tasks
32
+ routes
33
+ end
34
+
35
+ # gets all api routes
36
+ def routes
37
+ desc 'shows all routes'
38
+ task routes: :environment do
39
+ print_routes api_routes
40
+ end
41
+ end
42
+
43
+ # helper methods
44
+ #
45
+ def print_routes(routes_array)
46
+ routes_array.each do |route|
47
+ puts "\t#{route[:verb].ljust(7)}#{route[:path].ljust(42)}#{route[:description]}"
48
+ end
49
+ end
50
+
51
+ def build_path(route)
52
+ path = route.path
53
+
54
+ path.sub!(/\(\.\w+?\)$/, '')
55
+ path.sub!('(.:format)', '')
56
+
57
+ if route.version
58
+ path.sub!(':version', route.version.to_s)
59
+ else
60
+ path.sub!('/:version', '')
61
+ end
62
+
63
+ path
64
+ end
65
+
66
+ def app
67
+ api_class.new
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # CRUD examples
4
+ #
5
+ # for single
6
+ RSpec.shared_examples 'single CRUD' do |base_path: '/api/v1', resource: ''|
7
+ it_behaves_like 'POST', base_path: base_path, resource: resource
8
+ it_behaves_like 'GET one', base_path: base_path, resource: resource
9
+ it_behaves_like 'PUT one', base_path: base_path, resource: resource
10
+ it_behaves_like 'PATCH one', base_path: base_path, resource: resource
11
+ it_behaves_like 'DELETE one', base_path: base_path, resource: resource
12
+ end
13
+ #
14
+ # for plural
15
+ RSpec.shared_examples 'plural CRUD' do |base_path: '/api/v1', resource: '', key: nil|
16
+ it_behaves_like 'POST', base_path: base_path, resource: resource
17
+ it_behaves_like 'GET all', base_path: base_path, resource: resource
18
+ it_behaves_like 'GET specific', base_path: base_path, resource: resource, key: key
19
+ it_behaves_like 'PUT specific', base_path: base_path, resource: resource, key: key
20
+ it_behaves_like 'PATCH specific', base_path: base_path, resource: resource, key: key
21
+ it_behaves_like 'DELETE specific', base_path: base_path, resource: resource, key: key
22
+ end
23
+
24
+ # singular forms
25
+ #
26
+ RSpec.shared_examples 'POST' do |base_path: '/api/v1', resource: ''|
27
+ let(:route) { "#{base_path}/#{resource}" }
28
+
29
+ subject { post route }
30
+ specify { expect(subject.status).to eql 201 }
31
+ end
32
+
33
+ RSpec.shared_examples 'GET one' do |base_path: '/api/v1', resource: ''|
34
+ let(:route) { "#{base_path}/#{resource}" }
35
+
36
+ subject { get route }
37
+ specify { expect(subject.status).to eql 200 }
38
+ end
39
+
40
+ RSpec.shared_examples 'PUT one' do |base_path: '/api/v1', resource: ''|
41
+ let(:route) { "#{base_path}/#{resource}" }
42
+
43
+ subject { put route }
44
+ specify { expect(subject.status).to eql 200 }
45
+ end
46
+
47
+ RSpec.shared_examples 'PATCH one' do |base_path: '/api/v1', resource: ''|
48
+ let(:route) { "#{base_path}/#{resource}" }
49
+
50
+ subject { patch route }
51
+ specify { expect(subject.status).to eql 200 }
52
+ end
53
+
54
+ RSpec.shared_examples 'DELETE one' do |base_path: '/api/v1', resource: ''|
55
+ let(:route) { "#{base_path}/#{resource}" }
56
+
57
+ subject { delete route }
58
+ specify { expect(subject.status).to eql 204 }
59
+ end
60
+
61
+ # plural forms
62
+ #
63
+ RSpec.shared_examples 'POST' do |base_path: '/api/v1', resource: '', key: nil|
64
+ let(:route) { "#{base_path}/#{resource}" }
65
+ let(:specific_route) { "#{route}/#{key}" }
66
+
67
+ subject { post route }
68
+ specify { expect(subject.status).to eql 201 }
69
+ end
70
+
71
+ RSpec.shared_examples 'GET all' do |base_path: '/api/v1', resource: '', key: nil|
72
+ let(:route) { "#{base_path}/#{resource}" }
73
+ let(:specific_route) { "#{route}/#{key}" }
74
+
75
+ subject { get route }
76
+ specify { expect(subject.status).to eql 200 }
77
+ end
78
+
79
+ RSpec.shared_examples 'GET specific' do |base_path: '/api/v1', resource: '', key: nil|
80
+ let(:route) { "#{base_path}/#{resource}" }
81
+ let(:specific_route) { "#{route}/#{key}" }
82
+
83
+ subject { get specific_route }
84
+ specify { expect(subject.status).to eql 200 }
85
+ end
86
+
87
+ RSpec.shared_examples 'PUT specific' do |base_path: '/api/v1', resource: '', key: nil|
88
+ let(:route) { "#{base_path}/#{resource}" }
89
+ let(:specific_route) { "#{route}/#{key}" }
90
+
91
+ subject { put specific_route }
92
+ specify { expect(subject.status).to eql 200 }
93
+ end
94
+
95
+ RSpec.shared_examples 'PATCH specific' do |base_path: '/api/v1', resource: '', key: nil|
96
+ let(:route) { "#{base_path}/#{resource}" }
97
+ let(:specific_route) { "#{route}/#{key}" }
98
+
99
+ subject { patch specific_route }
100
+ specify { expect(subject.status).to eql 200 }
101
+ end
102
+
103
+ RSpec.shared_examples 'DELETE specific' do |base_path: '/api/v1', resource: '', key: nil|
104
+ let(:route) { "#{base_path}/#{resource}" }
105
+ let(:specific_route) { "#{route}/#{key}" }
106
+
107
+ subject { delete specific_route }
108
+ specify { expect(subject.status).to eql 204 }
109
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module Starter
3
+ VERSION = '0.2.0'
4
+ end
@@ -0,0 +1,15 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ Exclude:
5
+ - '**/tmp/**/*'
6
+ - '**/script/**/*'
7
+ UseCache: true
8
+ TargetRubyVersion: 2.3
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ - 'api/endpoints/**/*'
13
+
14
+ Metrics/LineLength:
15
+ Max: 120
@@ -0,0 +1,28 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-10-18 20:40:59 +0200 using RuboCop version 0.44.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
11
+ # URISchemes: http, https
12
+ Metrics/LineLength:
13
+ Max: 120
14
+
15
+ # Offense count: 1
16
+ # Configuration parameters: CountComments.
17
+ Metrics/MethodLength:
18
+ Max: 10
19
+
20
+ Style/AsciiComments:
21
+ Enabled: false
22
+
23
+ # Offense count: 6
24
+ Style/Documentation:
25
+ Exclude:
26
+ - 'spec/**/*'
27
+ - 'api/**/*'
28
+ - 'lib/**/*'