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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 52f430416f92875210e64914e6fe61c29d4c3e56
4
+ data.tar.gz: 77f33daa8ca7ef7f49e4415acaf2261edc888969
5
+ SHA512:
6
+ metadata.gz: 94908b48037df0376311ddb26b61e408e99b9fd65e017fbb484a121cdaacea7fc65fe12fc7eae1930ba5239becefddf5555ecca2d02599ec9b05cafe570ae48a
7
+ data.tar.gz: f089a230198355841150ae7353973e0fc8180c50e2e742f98ed63363c193b48ac199f46694238e2a516ebd0ce970028e876bcae079f97962820c500962919b90
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ .DS_Store
2
+ .rvmrc
3
+ .redcar
4
+ .irbrc
5
+ .bundle
6
+ log
7
+ Gemfile.lock
8
+ docker-compose.yml
9
+ Dockerfile
10
+ tmp/
11
+ .rspec
12
+ pkg/
data/.rubocop.yml ADDED
@@ -0,0 +1,36 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ Exclude:
5
+ - '**/bin/**/*'
6
+ - '**/tmp/**/*'
7
+ - '**/script/**/*'
8
+ - grape-starter.gemspec
9
+ UseCache: true
10
+ TargetRubyVersion: 2.3
11
+
12
+ Metrics/BlockLength:
13
+ Exclude:
14
+ - 'spec/**/*'
15
+
16
+ Metrics/LineLength:
17
+ Max: 120
18
+
19
+ Style/AccessorMethodName:
20
+ Exclude:
21
+ - 'lib/starter/builder/template_files.rb'
22
+ - 'lib/starter/builder/template_endpoints.rb'
23
+
24
+ Style/AsciiComments:
25
+ Enabled: false
26
+
27
+ Style/IndentationWidth:
28
+ Exclude:
29
+ - 'lib/starter/builder/template_files.rb'
30
+ - 'lib/starter/builder/template_endpoints.rb'
31
+
32
+ Style/Documentation:
33
+ Exclude:
34
+ - 'template/**/*'
35
+ - 'lib/**/*'
36
+ - 'spec/**/*'
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,12 @@
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: CountComments.
11
+ Metrics/MethodLength:
12
+ Max: 13
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+
3
+ language: ruby
4
+ rvm:
5
+ - 2.3.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ ### 0.1.8
2
+
3
+ - adds request specs shared examples
4
+
5
+ ### 0.1.7
6
+
7
+ - corrects path param for specific endpoints
8
+
9
+ ### 0.1.6
10
+
11
+ - corrects adding of endpoints, if no http verb was given
12
+
13
+ ### 0.1.5
14
+
15
+ - adds flag for entity creating
16
+
17
+ ### 0.1.4
18
+
19
+ - version bump v0.1.4
20
+ - moves back dependencies to gemspec
21
+ - adds rubygems badge
22
+ - cleans up dependencies …
23
+ - updates readme
24
+ - version bump v0.1.2
25
+ - adds `force` option to add
26
+ - version bump v0.1.1
27
+ - adds specifying http verbs
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ source 'http://rubygems.org'
3
+
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Peter Scholz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ [![Codeship Status for LeFnord/grape-starter](https://app.codeship.com/projects/91e08e60-9600-0134-5571-4a8607aa1ae3/status?branch=master)](https://app.codeship.com/projects/186901)
2
+ [![Gem Version](https://badge.fury.io/rb/grape-starter.svg)](https://badge.fury.io/rb/grape-starter)
3
+ [![Inline docs](http://inch-ci.org/github/LeFnord/grape-starter.svg?branch=master)](http://inch-ci.org/github/LeFnord/grape-starter)
4
+
5
+ # Grape Starter
6
+
7
+ Is a tool to help you to build up a skeleton for a [Grape](http://github.com/ruby-grape/grape) API mounted on [Rack](https://github.com/rack/rack) ready to run.
8
+ [grape-swagger](http://github.com/ruby-grape/grape-swagger) would be used to generate a [OAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) compatible documentation.
9
+
10
+
11
+ ## Usage
12
+
13
+ #### Install it
14
+ ```
15
+ $ gem install grape-starter
16
+ ```
17
+
18
+ #### Create a new project
19
+ ```
20
+ $ grape-starter new awesome_api
21
+ ```
22
+
23
+ This command creates a folder named `awesome_api` containing the skeleton. With following structure:
24
+
25
+ ```
26
+ ├── <Standards>
27
+ ├── api
28
+ │   ├── base.rb # the main API class, all other endpoints would be mounted in it
29
+ │   ├── endpoints # contains the endpoint file for a resource
30
+ │   │   └── root.rb # root is always available, it exposes all routes/endpoints, disable by comment out in base.rb
31
+ │   └── entities # contains the entity representation of the reource, if wanted
32
+ │   └── route.rb
33
+ ├── config # base configuration
34
+ │   └── …
35
+ ├── config.ru # Rack it up
36
+ ├── lib # contains the additional lib file for a resource
37
+ │   ├── api
38
+ │   │   └── version.rb
39
+ │   └── api.rb
40
+ ├── script # setup / server / test etc.
41
+ │   └── …
42
+ └── spec # RSpec
43
+    └── …
44
+ ```
45
+
46
+ To run it, go into awesome_api folder, start the server
47
+ ```
48
+ $ cd awesome_api
49
+ $ ./script/server
50
+ ```
51
+ the API is now accessible under: [http://localhost:9292/api/v1/root](http://localhost:9292/api/v1/root)
52
+
53
+ More could be found in [README](template/README.md).
54
+
55
+ #### Add resources
56
+ ```
57
+ $ grape-starter add foo
58
+ ```
59
+ to add CRUD endpoints for resource foo. For more options, see command help.
60
+
61
+ This adds endpoint and lib file and belonging specs, and a mount entry in base.rb.
62
+
63
+ ## Contributing
64
+
65
+ Bug reports and pull requests are welcome on GitHub at https://github.com/LeFnord/grape-starter.
66
+
67
+
68
+ ## License
69
+
70
+ The gem is available as open source under the terms of the [MIT License](LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require 'bundler/gem_tasks'
3
+
4
+ require 'rake'
5
+
6
+ require 'rspec/core'
7
+ require 'rspec/core/rake_task'
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ require 'rubocop/rake_task'
12
+ RuboCop::RakeTask.new(:rubocop)
13
+
14
+ task default: [:rubocop, :spec]
data/bin/grape-starter ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+
6
+ require 'pry'
7
+ require 'gli'
8
+ require 'starter'
9
+
10
+ include GLI::App
11
+
12
+ program_desc 'Create initial grape api skeleton'
13
+
14
+ version Starter::VERSION
15
+
16
+ subcommand_option_handling :normal
17
+ arguments :strict
18
+
19
+ desc 'overwrites existend stuff'
20
+ switch [:f, :force], negatable: false
21
+
22
+ desc 'Create initial grape api skeleton'
23
+ arg_name 'project name'
24
+
25
+ command :new do |c|
26
+
27
+ c.action do |global_options, _, args|
28
+ dir = args.empty? ? nil : File.join(Dir.getwd, args.first)
29
+
30
+ case
31
+ when args.empty? || dir.nil?
32
+ exit_now! 'no name given: starter new project'
33
+ when Dir.exist?(dir) && !global_options[:force]
34
+ exit_now! 'project exist: -f to overwrite'
35
+ end
36
+
37
+ $stdout.puts "created: #{args.first}"
38
+ starter_gem = Gem::Specification.find_by_name('grape-starter').gem_dir
39
+
40
+ src = File.join(starter_gem, 'template', '.')
41
+ FileUtils.copy_entry src, dir
42
+
43
+ FileUtils.cd(dir) do
44
+ # TODO:
45
+ $stdout.puts `bundle install`
46
+ $stdout.puts `bundle exec rubocop -a`
47
+ $stdout.puts `git init`
48
+ end
49
+ end
50
+ end
51
+
52
+ desc 'Adds a new resource - run from inside the project'
53
+ long_desc "run this command from inside the project
54
+ hereby the the given resource name
55
+ can be given in form of
56
+ 'foo(s)', 'foo_bar(s)''"
57
+ arg_name 'resource [post* get* put* patch* delete*]'
58
+ command :add do |c|
59
+ c.desc 'adds entity file'
60
+ c.switch [:e, :entity], negatable: false
61
+
62
+ c.action do |global_options, options, args|
63
+ exit_now! 'no resource given' if args.empty?
64
+
65
+ resource = args.shift
66
+ set = args
67
+
68
+ begin
69
+ builder_options = global_options.merge(set: set).merge(options)
70
+ Starter::Builder.call!(resource, builder_options)
71
+ created_files = Starter::Builder.save
72
+
73
+ `bundle exec rubocop -a #{created_files.join(' ')}`
74
+ $stdout.puts "added resource: #{resource}"
75
+ rescue => e
76
+ exit_now! e
77
+ end
78
+ end
79
+ end
80
+
81
+ desc 'Removes a resource - run from inside the project'
82
+ arg_name 'resource'
83
+ command :remove do |c|
84
+ # c.desc 'adds entity file'
85
+ # c.switch [:e, :entity], negatable: false
86
+
87
+ c.action do |global_options, options, args|
88
+ exit_now! 'no resource given' if args.empty?
89
+ resource = args.first
90
+
91
+ Starter::Builder.remove!(resource)
92
+
93
+ $stdout.puts "removed resource: #{resource}"
94
+ end
95
+ end
96
+
97
+
98
+ pre do |_global, _command, _options, _args|
99
+ # Pre logic here
100
+ # Return true to proceed; false to abort and not call the
101
+ # chosen command
102
+ # Use skips_pre before a command to skip this block
103
+ # on that command only
104
+ true
105
+ end
106
+
107
+ post do |global, command, options, args|
108
+ # Post logic here
109
+ # Use skips_post before a command to skip this
110
+ # block on that command only
111
+ end
112
+
113
+ on_error do |_exception|
114
+ # Error logic here
115
+ # return false to skip default error handling
116
+ true
117
+ end
118
+
119
+ exit run(ARGV)
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'starter/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'grape-starter'
9
+ spec.version = Starter::VERSION
10
+ spec.authors = ['LeFnord']
11
+ spec.email = ['pscholz.le@gmail.com']
12
+
13
+ spec.summary = 'Create a Grape Rack skeleton'
14
+ spec.description = 'CLI to create a API skeleton based on Grape and Rack'
15
+ spec.homepage = 'https://github.com/LeFnord/grape-starter'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'bin'
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_dependency 'gli', '~> 2.14'
26
+ spec.add_dependency 'activesupport', '~> 5.0'
27
+ spec.add_dependency 'rubocop', '~> 0.40'
28
+
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'grape', '~> 0.18'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ spec.add_development_dependency 'rack-test'
33
+ spec.add_development_dependency 'pry'
34
+ spec.add_development_dependency 'awesome_print'
35
+
36
+ end
data/lib/starter.rb ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ require 'awesome_print'
3
+
4
+ require 'starter/version'
5
+ require 'starter/builder'
6
+
7
+ module Starter
8
+ autoload :Rake, 'starter/rake/grape_tasks'
9
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ require 'active_support/core_ext/string'
3
+
4
+ module Starter
5
+ require 'starter/builder/names'
6
+ require 'starter/builder/template_files'
7
+ require 'starter/builder/template_endpoints'
8
+
9
+ class Builder
10
+ extend Starter::Names
11
+ extend Template::Files
12
+ extend Template::Endpoints
13
+
14
+ class << self
15
+ attr_reader :resource, :set, :force, :entity
16
+
17
+ def call!(resource, options = {})
18
+ @resource = resource
19
+ @set = options[:set]
20
+ @force = options[:force]
21
+ @entity = options[:entity]
22
+
23
+ self
24
+ end
25
+
26
+ def remove!(resource)
27
+ @resource = resource
28
+
29
+ files_to_remove = file_list.map { |x| send("#{x}_name") }
30
+ FileUtils.rm files_to_remove
31
+ end
32
+
33
+ def save
34
+ file_list.each do |new_file|
35
+ save_file(new_file)
36
+ end
37
+
38
+ add_moint_point
39
+
40
+ file_list.map { |x| send("#{x}_name") }
41
+ end
42
+
43
+ def endpoints
44
+ content(endpoint_set).join("\n\n")
45
+ end
46
+
47
+ def endpoint_specs
48
+ content(endpoint_set.map { |x| "#{x}_spec" }).join("\n")
49
+ end
50
+
51
+ private
52
+
53
+ def file_list
54
+ standards = %w(api_file lib_file api_spec lib_spec)
55
+
56
+ entity ? standards + ['entity_file'] : standards
57
+ end
58
+
59
+ def save_file(new_file)
60
+ new_file_name = "#{new_file}_name"
61
+ should_raise?(send(new_file_name))
62
+
63
+ File.open(send(new_file_name), 'w+') { |file| file.write(send(new_file.strip_heredoc)) }
64
+ end
65
+
66
+ def should_raise?(file)
67
+ raise StandardError, '… resource exists' if File.exist?(file) && !force
68
+ end
69
+
70
+ def add_moint_point
71
+ file = File.read(api_base_file_name)
72
+ occurence = file.scan(/(\s+mount.*?\n)/).last.first
73
+ replacement = occurence + " mount Endpoints::#{klass_name}\n"
74
+ file.sub!(occurence, replacement)
75
+ File.open(api_base_file_name, 'w') { |f| f.write(file) }
76
+ end
77
+
78
+ def endpoint_set
79
+ crud_set = singular? ? singular_one : crud
80
+ return crud_set if set.blank?
81
+
82
+ crud_set.each_with_object([]) { |x, memo| set.map { |y| memo << x if x.to_s.start_with?(y) } }
83
+ end
84
+
85
+ def content(set)
86
+ set.map { |x| send(x) }
87
+ end
88
+ end
89
+ end
90
+ end