grape-starter 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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