grapevine 0.4.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/.rspec +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +55 -0
- data/Rakefile +1 -0
- data/bin/grapevine +7 -0
- data/grapevine.gemspec +31 -0
- data/lib/grapevine.rb +11 -0
- data/lib/grapevine/api.rb +20 -0
- data/lib/grapevine/representer.rb +11 -0
- data/lib/grapevine/structure/grapevine.rb +96 -0
- data/lib/grapevine/structure/grapevine_skeleton.rb +78 -0
- data/lib/grapevine/structure/grapevine_structure/.gitignore.tt +3 -0
- data/lib/grapevine/structure/grapevine_structure/.rspec.tt +3 -0
- data/lib/grapevine/structure/grapevine_structure/Gemfile.tt +29 -0
- data/lib/grapevine/structure/grapevine_structure/README.md.tt +2 -0
- data/lib/grapevine/structure/grapevine_structure/Rakefile.tt +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/context/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/data/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/decorators/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/helpers/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/information/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/representers/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/app/representers/modules/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/config.ru.tt +2 -0
- data/lib/grapevine/structure/grapevine_structure/config/application.rb.tt +21 -0
- data/lib/grapevine/structure/grapevine_structure/config/boot.rb.tt +41 -0
- data/lib/grapevine/structure/grapevine_structure/config/initializers/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/lib/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/spec/.gitkeep +0 -0
- data/lib/grapevine/structure/grapevine_structure/spec/initializers/start_server_spec.rb.tt +9 -0
- data/lib/grapevine/structure/templates/ActiverecordRakefile.tt +32 -0
- data/lib/grapevine/structure/templates/SequelRakefile.tt +83 -0
- data/lib/grapevine/structure/templates/activerecord_db_config.rb.tt +21 -0
- data/lib/grapevine/structure/templates/config.yml.tt +15 -0
- data/lib/grapevine/structure/templates/db/migrate/.gitkeep +0 -0
- data/lib/grapevine/structure/templates/db/schema.rb.tt +0 -0
- data/lib/grapevine/structure/templates/env.sample.tt +22 -0
- data/lib/grapevine/structure/templates/routes.rb.tt +24 -0
- data/lib/grapevine/structure/templates/sequel_db_config.rb.tt +25 -0
- data/lib/grapevine/structure/templates/spec_helper.rb.tt +17 -0
- data/lib/grapevine/version.rb +3 -0
- data/spec/grapevine/api_spec.rb +20 -0
- data/spec/sandbox/.gitkepp +0 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/structure/create_app_structure_spec.rb +56 -0
- data/spec/structure/templates_spec.rb +23 -0
- metadata +230 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jaime Andres
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Grapevine
|
2
|
+
|
3
|
+
[Grape](https://github.com/intridea/grape) is a great micro-framework to create REST-like APIs, however its strongest point is, at the same time, its weakest point: there's no structure, so you can decide how to structure your code, how to define your app architecture and that could lead to ... a big mess, because a project without order could become unmaintainable.
|
4
|
+
|
5
|
+
Grapevine is an opinionated structure - with desires to become a framework ;) - to use [Grape](https://github.com/intridea/grape) to create REST-like APIs.
|
6
|
+
|
7
|
+
This structure includes [roar](github.com/apotonick/roar) for hypermediaAPI in case you want to deliver your api that way. It also includes rspec and debugger so you can start testing your api as soon as you begin writing it.
|
8
|
+
|
9
|
+
Please refer to docs so you can see what you get besides the possibility to start with an structure
|
10
|
+
|
11
|
+
Last but not least (in fact I think this is the main feature of grapevine), it's the structure which tries to keep good practices for class separations and mainly around the DCI concept. Keep in mind that instead of using Interaction the proposed name is Information, why? because when you interact with a service you're asking it for information.
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'grapevine'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install grapevine
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
|
31
|
+
## Credits
|
32
|
+
All this work couldn't be possible without the existence of great projects like, so please refer to them to understand how they behave and how they can
|
33
|
+
be used, that way you'll be able to design and implement your api with better pratices.
|
34
|
+
|
35
|
+
* [grape](https://github.com/intridea/grape)
|
36
|
+
* [roar](github.com/apotonick/roar)
|
37
|
+
* [thor](https://github.com/wycats/thor)
|
38
|
+
* [thin](https://github.com/macournoyer/thin/)
|
39
|
+
* [rack](https://github.com/rack/rack)
|
40
|
+
* [sequel](https://github.com/jeremyevans/sequel)
|
41
|
+
* [standalone-migrations](https://github.com/thuss/standalone-migrations)
|
42
|
+
* [debugger](https://github.com/cldwalker/debugger)
|
43
|
+
|
44
|
+
This is not the complete list, this is just the list of those gems I'm declaring directly, so for all hidden gems thank you so much to exist.
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create new Pull Request
|
53
|
+
|
54
|
+
## License
|
55
|
+
This content is released under the [MIT License](LICENSE.txt).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/grapevine
ADDED
data/grapevine.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'grapevine/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "grapevine"
|
8
|
+
gem.version = Grapevine::VERSION
|
9
|
+
gem.authors = ["Jaime Andres"]
|
10
|
+
gem.email = ["andresdavila6@gmail.com"]
|
11
|
+
gem.description = %q{creates a work environment including grape, roar, rspec, sequel to develop REST architectures}
|
12
|
+
gem.summary = %q{REST architecture with DCI in mind thanks to grape}
|
13
|
+
gem.homepage = "http://jaimeandres.github.com/grapevine/"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# dependencies
|
21
|
+
gem.add_dependency "yard"
|
22
|
+
gem.add_dependency "thor"
|
23
|
+
gem.add_dependency "json"
|
24
|
+
gem.add_dependency "grape"
|
25
|
+
gem.add_dependency "i18n"
|
26
|
+
gem.add_dependency "roar"
|
27
|
+
|
28
|
+
# dev_dependencies
|
29
|
+
gem.add_development_dependency "rspec"
|
30
|
+
gem.add_development_dependency "debugger"
|
31
|
+
end
|
data/lib/grapevine.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Grapevine
|
2
|
+
class API < Grape::API
|
3
|
+
|
4
|
+
# It will call grape#helpers method for each helper module included
|
5
|
+
# @param format [Array] Helpers Modules to be included in the app
|
6
|
+
def self.mount_helpers(app_helpers=[])
|
7
|
+
app_helpers.each do |helper|
|
8
|
+
helpers helper
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# It will call grape#mount method for each route to include
|
13
|
+
# @param format [Array] Routes Class to be included in the main app
|
14
|
+
def self.mount_routes(app_routes=[])
|
15
|
+
app_routes.each do |route|
|
16
|
+
mount route
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'roar/representer/json'
|
2
|
+
require 'roar/representer/feature/hypermedia'
|
3
|
+
|
4
|
+
# Include this module as Grapevine::Representer to include all roar methods without worrying
|
5
|
+
# to require roar lib and include the corresponding modules
|
6
|
+
module Grapevine
|
7
|
+
module Representer
|
8
|
+
include Roar::Representer::JSON
|
9
|
+
include Roar::Representer::Feature::Hypermedia
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/grapevine_skeleton.rb')
|
3
|
+
|
4
|
+
module Structure
|
5
|
+
class Grapevine < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.dirname(__FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
method_option :withdb, type: :string, default: ''
|
13
|
+
method_option :dbms, type: :string, default: 'pg'
|
14
|
+
desc "new <AppName> --withdb sequel|activerecord --dbms pg|mysql2", "create a new app, --withdb is optional"
|
15
|
+
def new(app_name)
|
16
|
+
error_message = "new <AppName> --withdb sequel|activerecord --dbms pg|mysql2", "create a new app, --withdb is optional"
|
17
|
+
p error_message if options.include?(:withdb) && withdb(options[:witdb]) == ''
|
18
|
+
|
19
|
+
a = dbms(options[:dbms])
|
20
|
+
Structure::GrapevineSkeleton.start([app_name, withdb(options[:withdb]), dbms(options[:dbms])])
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "add_api_version", "creates a new routes.rb file under the new incremented version folder"
|
24
|
+
def add_api_version
|
25
|
+
|
26
|
+
if Dir.exists?(information_path)
|
27
|
+
version = "v#{api_version}"
|
28
|
+
|
29
|
+
Dir.mkdir("#{information_path}/#{version}")
|
30
|
+
|
31
|
+
template(source, destination(version), opts_with_version(version))
|
32
|
+
else
|
33
|
+
p "it looks like you're not inside a grapevine project"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def dbms(options)
|
40
|
+
if !options.nil? || options =~ /^(pg|mysql2)$/
|
41
|
+
options
|
42
|
+
else
|
43
|
+
"pg"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def withdb(options)
|
48
|
+
if !options.nil? && options =~ /^(sequel|activerecord)$/
|
49
|
+
options
|
50
|
+
else
|
51
|
+
""
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def information_path
|
56
|
+
"app/information"
|
57
|
+
end
|
58
|
+
|
59
|
+
def application_name
|
60
|
+
file = File.open('config/application.rb', 'r')
|
61
|
+
file.read.each_line do |line|
|
62
|
+
if line =~ /module/
|
63
|
+
return line.gsub('module ', '')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def api_version
|
69
|
+
api_version = [0]
|
70
|
+
|
71
|
+
Dir.entries(information_path).each do |version|
|
72
|
+
if version =~ /v\d/
|
73
|
+
api_version << version[1..-1].to_i
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
api_version.uniq.sort.last + 1
|
78
|
+
end
|
79
|
+
|
80
|
+
def opts_with_version(version)
|
81
|
+
{
|
82
|
+
version: version,
|
83
|
+
app_name: application_name,
|
84
|
+
verbose: false
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def source
|
89
|
+
File.dirname(__FILE__) + '/templates/routes.rb.tt'
|
90
|
+
end
|
91
|
+
|
92
|
+
def destination(version)
|
93
|
+
"#{information_path}/#{version}/routes.rb"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
|
3
|
+
module Structure
|
4
|
+
class GrapevineSkeleton < Thor::Group
|
5
|
+
include Thor::Actions
|
6
|
+
|
7
|
+
def self.source_root
|
8
|
+
File.dirname(__FILE__)
|
9
|
+
end
|
10
|
+
|
11
|
+
argument :app_name, type: :string
|
12
|
+
argument :withdb, type: :string
|
13
|
+
argument :dbms, type: :string
|
14
|
+
def create_app
|
15
|
+
exist_directory!
|
16
|
+
create_directory('grapevine_structure', app_directory)
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_spec_helper
|
20
|
+
create_template('spec_helper.rb', 'spec/spec_helper.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_db_structure
|
24
|
+
unless withdb.empty?
|
25
|
+
create_template('env.sample', '.env.sample')
|
26
|
+
|
27
|
+
create_directory("#{templates_directory}/db", "#{app_directory}/db")
|
28
|
+
|
29
|
+
create_db_structure_for(withdb)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def return_to_initial_path
|
34
|
+
p "You can start developing #{app_directory} service ;)"
|
35
|
+
p "Don't forget to configure your .env file"
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def app_directory
|
41
|
+
app_name.underscore
|
42
|
+
end
|
43
|
+
|
44
|
+
def exist_directory!
|
45
|
+
raise Thor::Error, "Directory #{app_directory} exist" if File.directory?app_directory
|
46
|
+
end
|
47
|
+
|
48
|
+
def templates_directory
|
49
|
+
"#{File.dirname(__FILE__)}/templates"
|
50
|
+
end
|
51
|
+
|
52
|
+
def templates_source(template_file)
|
53
|
+
"#{templates_directory}/#{template_file}.tt"
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_template(source, target, conditions={})
|
57
|
+
template(templates_source(source), "#{app_directory}/#{target}", { verbose: false }.merge(conditions))
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_directory(source, target)
|
61
|
+
directory(source, target, { verbose: false })
|
62
|
+
end
|
63
|
+
|
64
|
+
def destination(version)
|
65
|
+
"#{information_path}/#{version}/routes.rb"
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_db_structure_for(orm)
|
69
|
+
create_template("#{orm.titleize}Rakefile", 'Rakefile', { force: true })
|
70
|
+
create_template("#{orm}_db_config.rb", 'config/initializers/db_config.rb')
|
71
|
+
|
72
|
+
if orm == 'activerecord'
|
73
|
+
create_template('config.yml', 'db/config.yml')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
ruby '1.9.3'
|
4
|
+
|
5
|
+
gem 'rake'
|
6
|
+
gem 'grapevine'
|
7
|
+
|
8
|
+
<% unless withdb.empty? %>
|
9
|
+
gem '<%= withdb %>'
|
10
|
+
|
11
|
+
<% if withdb == 'activerecord' %>
|
12
|
+
gem 'activerecord', '~> 3.2.12'
|
13
|
+
gem 'standalone_migrations', '~> 2.0.5'
|
14
|
+
|
15
|
+
<% elsif withdb == 'sequel' %>
|
16
|
+
gem 'sequel'
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
group :test do
|
21
|
+
gem 'rspec'
|
22
|
+
gem 'rack-test'
|
23
|
+
end
|
24
|
+
|
25
|
+
group :test, :development do
|
26
|
+
gem 'dotenv'
|
27
|
+
gem 'thin'
|
28
|
+
gem 'debugger'
|
29
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
module <%= app_name.camelize %>
|
4
|
+
class Application < Grapevine::API
|
5
|
+
|
6
|
+
# uncomment mount_helpers method and include all helpers you required from those declared in helpers folder
|
7
|
+
# e.g. mount_helpers([::AppHelpers, ::ContextHelpers])
|
8
|
+
#
|
9
|
+
# mount_helpers([])
|
10
|
+
|
11
|
+
# uncomment mount_helpers method and include all routes you required
|
12
|
+
# e.g. mount_routes([AppName::V1::Routes, ::MyCustomRoutes])
|
13
|
+
#
|
14
|
+
# mount_routes([])
|
15
|
+
|
16
|
+
get '/' do
|
17
|
+
{ home: "welcome to <%= app_name.camelize%>" }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
ENV['<%= app_name.camelize.upcase %>'] ||= 'development'
|
4
|
+
|
5
|
+
if ['development', 'test'].include?(ENV['<%= app_name.camelize.upcase %>'])
|
6
|
+
require 'dotenv'
|
7
|
+
Dotenv.load
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'grapevine'
|
11
|
+
|
12
|
+
# Set up gems listed in the Gemfile.
|
13
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
14
|
+
|
15
|
+
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
16
|
+
|
17
|
+
# Initializers
|
18
|
+
Dir[File.dirname(__FILE__) + '/initializers/*.rb'].each do |file|
|
19
|
+
require file
|
20
|
+
end
|
21
|
+
|
22
|
+
<% unless withdb.empty? %>
|
23
|
+
|
24
|
+
<% if withdb == 'activerecord' %>
|
25
|
+
|
26
|
+
require 'active_record'
|
27
|
+
<% elsif withdb == 'sequel' %>
|
28
|
+
|
29
|
+
require 'sequel'
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
# it's important to connect to the database
|
33
|
+
DbConfig.connect
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
# Application files
|
37
|
+
Dir[File.dirname(__FILE__) + '/../app/**/*.rb'].each do |file|
|
38
|
+
require file
|
39
|
+
end
|
40
|
+
|
41
|
+
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'tasks/standalone_migrations'
|
2
|
+
|
3
|
+
if ['development', 'test'].include?(ENV['<%= app_name.camelize.upcase %>'])
|
4
|
+
require 'dotenv'
|
5
|
+
require 'dotenv/tasks'
|
6
|
+
|
7
|
+
Dotenv.load
|
8
|
+
end
|
9
|
+
|
10
|
+
StandaloneMigrations::Configurator.environments_config do |env|
|
11
|
+
|
12
|
+
env.on ENV["<%= app_name.camelize.upcase %>"] do
|
13
|
+
|
14
|
+
if ENV["<%= app_name.camelize.upcase %>"] == 'test'
|
15
|
+
ENV['DATABASE'] = "#{ENV['DATABASE']}_test"
|
16
|
+
end
|
17
|
+
|
18
|
+
return {
|
19
|
+
<% if dbms == 'mysql' %>
|
20
|
+
socket: ENV['SOCKET'],
|
21
|
+
<% end %>
|
22
|
+
adapter: ENV['ADAPTER'],
|
23
|
+
host: ENV['HOST'],
|
24
|
+
port: ENV['PORT'],
|
25
|
+
username: ENV['USERNAME'],
|
26
|
+
password: ENV['PASSWORD'],
|
27
|
+
database: ENV['DATABASE'],
|
28
|
+
encoding: 'utf8'
|
29
|
+
}
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
require "sequel"
|
3
|
+
|
4
|
+
if ['development', 'test'].include?(ENV['<%= app_name.camelize.upcase %>'])
|
5
|
+
require 'dotenv'
|
6
|
+
require 'dotenv/tasks'
|
7
|
+
|
8
|
+
Dotenv.load
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace "db" do
|
12
|
+
|
13
|
+
if ENV["<%= app_name.camelize.upcase %>"] == 'test'
|
14
|
+
ENV['DATABASE'] = "#{ENV['DATABASE']}_test"
|
15
|
+
end
|
16
|
+
|
17
|
+
database_url = {
|
18
|
+
<% if dbms == 'mysql' %>
|
19
|
+
socket: ENV['SOCKET'],
|
20
|
+
<% end %>
|
21
|
+
adapter: ENV['ADAPTER'],
|
22
|
+
host: ENV['HOST'],
|
23
|
+
port: ENV['PORT'],
|
24
|
+
username: ENV['USERNAME'],
|
25
|
+
password: ENV['PASSWORD'],
|
26
|
+
database: ENV['DATABASE'],
|
27
|
+
encoding: 'utf8',
|
28
|
+
test: true
|
29
|
+
}
|
30
|
+
|
31
|
+
task :migrate do |t|
|
32
|
+
version = nil
|
33
|
+
Sequel.extension :migration
|
34
|
+
db = Sequel.connect(database_url)
|
35
|
+
|
36
|
+
puts "Running migrations..." unless ENV['RACK_ENV'] == 'test'
|
37
|
+
Sequel::Migrator.apply(db, 'db/migrate', version && version.to_i)
|
38
|
+
db.disconnect
|
39
|
+
|
40
|
+
Rake::Task["db:dump_schema"].execute
|
41
|
+
end
|
42
|
+
|
43
|
+
task :dump_schema do |t|
|
44
|
+
require 'sequel'
|
45
|
+
Sequel.extension :schema_dumper
|
46
|
+
schema_file="#{File.dirname(__FILE__)}/db/schema.rb"
|
47
|
+
db = Sequel.connect(database_url)
|
48
|
+
|
49
|
+
puts 'Dumping schema...' unless ENV['RACK_ENV'] == 'test'
|
50
|
+
open(schema_file, 'w') do |f|
|
51
|
+
f << db.dump_schema_migration(:same_db => false)
|
52
|
+
end
|
53
|
+
db.disconnect
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Creates a new migration file with the specified name"
|
57
|
+
task :new_migration, :name do |t, args|
|
58
|
+
name = args[:name] || ENV['name']
|
59
|
+
options = args[:options] || ENV['options']
|
60
|
+
|
61
|
+
unless name
|
62
|
+
puts "Error: must provide name of migration to generate."
|
63
|
+
puts "For example: rake #{t.name} name=add_field_to_form"
|
64
|
+
abort
|
65
|
+
end
|
66
|
+
|
67
|
+
migrations_dir = File.join("db", "migrate")
|
68
|
+
version ||= Time.now.utc.strftime("%Y%m%d%H%M%S")
|
69
|
+
filename = "#{version}_#{name}.rb"
|
70
|
+
|
71
|
+
FileUtils.mkdir_p(migrations_dir)
|
72
|
+
|
73
|
+
open(File.join(migrations_dir, filename), 'w') do |f|
|
74
|
+
f << (<<-EOS).gsub(" ", "")
|
75
|
+
Sequel.migration do
|
76
|
+
change do
|
77
|
+
end
|
78
|
+
end
|
79
|
+
EOS
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class DbConfig
|
2
|
+
|
3
|
+
def self.connect
|
4
|
+
|
5
|
+
if ENV["<%= app_name.camelize.upcase %>"] == 'test'
|
6
|
+
ENV['DATABASE'] = "#{ENV['DATABASE']}_test"
|
7
|
+
end
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection(
|
10
|
+
{
|
11
|
+
adapter: ENV['ADAPTER'],
|
12
|
+
host: ENV['HOST'],
|
13
|
+
port: ENV['PORT'],
|
14
|
+
database: ENV['DATABASE'],
|
15
|
+
username: ENV['USERNAME'],
|
16
|
+
password: ENV['PASSWORD'],
|
17
|
+
encoding: 'utf8'
|
18
|
+
}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
development:
|
2
|
+
host: <%= ENV['HOST'] %>
|
3
|
+
port: <%= ENV['PORT'] %>
|
4
|
+
adapter: <%= ENV['ADAPTER'] %>
|
5
|
+
database: <%= ENV['DATABASE'] %>
|
6
|
+
username: <%= ENV['USERNAME'] %>
|
7
|
+
password: <%= ENV['PASSWORD'] %>
|
8
|
+
|
9
|
+
test:
|
10
|
+
host: <%= ENV['HOST'] %>
|
11
|
+
port: <%= ENV['PORT'] %>
|
12
|
+
adapter: <%= ENV['ADAPTER'] %>
|
13
|
+
database: <%= ENV['DATABASE'] %> + "_test"
|
14
|
+
username: <%= ENV['USERNAME'] %>
|
15
|
+
password: <%= ENV['PASSWORD'] %>
|
File without changes
|
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Database access
|
2
|
+
HOST=<host>
|
3
|
+
PORT=<port>
|
4
|
+
DATABASE=<database_name>
|
5
|
+
|
6
|
+
<% if dbms == 'pg' %>
|
7
|
+
|
8
|
+
<% if withdb == 'activerecord' %>
|
9
|
+
|
10
|
+
ADAPTER=postgresql
|
11
|
+
<% elsif withdb == 'sequel' %>
|
12
|
+
|
13
|
+
ADAPTER=postgres
|
14
|
+
<% end %>
|
15
|
+
<% elsif dbms == 'mysql2' %>
|
16
|
+
|
17
|
+
ADAPTER=mysql2
|
18
|
+
SOCKET=<socket>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
USERNAME=<username>
|
22
|
+
PASSWORD=<password>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module <%= config[:app_name] %>
|
2
|
+
module <%= config[:version].upcase %>
|
3
|
+
class Routes < Grapevine::API
|
4
|
+
|
5
|
+
version '<%= config[:version] %>', using: :path
|
6
|
+
|
7
|
+
# uncomment mount_helpers method and include all helpers you required from those declared in helpers folder
|
8
|
+
# e.g. mount_helpers([::AppHelpers, ::ContextHelpers])
|
9
|
+
#
|
10
|
+
# mount_helpers([])
|
11
|
+
|
12
|
+
# uncomment mount_helpers method and include all routes you required
|
13
|
+
# e.g. mount_routes([AppName::V1::Routes, ::MyCustomRoutes])
|
14
|
+
#
|
15
|
+
# mount_routes([])
|
16
|
+
|
17
|
+
resource :test_route do
|
18
|
+
get '/' do
|
19
|
+
{ result: "this is the test route resource of <%= config[:version] %>" }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class DbConfig
|
2
|
+
|
3
|
+
def self.connect
|
4
|
+
|
5
|
+
if ENV["<%= app_name.camelize.upcase %>"] == 'test'
|
6
|
+
ENV['DATABASE'] = "#{ENV['DATABASE']}_test"
|
7
|
+
end
|
8
|
+
|
9
|
+
Sequel::Model.plugin :timestamps
|
10
|
+
Sequel::Model.plugin :validation_helpers
|
11
|
+
|
12
|
+
|
13
|
+
database = {
|
14
|
+
adapter: ENV['ADAPTER'],
|
15
|
+
host: ENV['HOST'],
|
16
|
+
port: ENV['PORT'],
|
17
|
+
database: ENV['DATABASE'],
|
18
|
+
username: ENV['USERNAME'],
|
19
|
+
password: ENV['PASSWORD'],
|
20
|
+
encoding: 'utf8'
|
21
|
+
}
|
22
|
+
|
23
|
+
Sequel::Model.db = Sequel.connect(database)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
ENV["<%= app_name.camelize.upcase %>"] ||= 'test'
|
4
|
+
|
5
|
+
require File.expand_path("../../config/application", __FILE__)
|
6
|
+
|
7
|
+
require 'debugger'
|
8
|
+
require 'rack'
|
9
|
+
require 'rack/test'
|
10
|
+
|
11
|
+
def app
|
12
|
+
<%= app_name.camelize %>::Application
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.include Rack::Test::Methods
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grapevine::API do
|
4
|
+
|
5
|
+
module Test
|
6
|
+
end
|
7
|
+
|
8
|
+
subject { Class.new(Grapevine::API) }
|
9
|
+
|
10
|
+
def app; subject end
|
11
|
+
|
12
|
+
it 'should require grape, json' do
|
13
|
+
!!defined?(JSON).should == true
|
14
|
+
!!defined?(GRAPE).should == true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should include helpers' do
|
18
|
+
subject.mount_helpers([Test]).include?(Test).should == true
|
19
|
+
end
|
20
|
+
end
|
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Create a Grapevine App' do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
FileUtils.cd destination_root
|
7
|
+
end
|
8
|
+
|
9
|
+
after :each do
|
10
|
+
FileUtils.cd destination_root
|
11
|
+
FileUtils.remove_dir 'foo_app'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should create the app home directory' do
|
15
|
+
Structure::Grapevine.new.new(app_name)
|
16
|
+
FileUtils.cd destination_root
|
17
|
+
|
18
|
+
Dir.exist?('foo_app').should == true
|
19
|
+
Dir.entries('foo_app').include?('app').should == true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should not create an app if the name exists' do
|
23
|
+
Dir.mkdir 'foo_app'
|
24
|
+
Structure::Grapevine.new.new(app_name).should == nil
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'Templates declaration' do
|
28
|
+
before do
|
29
|
+
Structure::Grapevine.new.new(app_name)
|
30
|
+
FileUtils.cd destination_root
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should create config.ru correctly' do
|
34
|
+
file = File.open('foo_app/config.ru', 'r')
|
35
|
+
file.read.should include "#{app_name}::Application"
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should create spec_helper and first spec' do
|
39
|
+
File.exists?('foo_app/spec/spec_helper.rb').should == true
|
40
|
+
File.exists?('foo_app/spec/initializers/start_server_spec.rb').should == true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'db configuration' do
|
45
|
+
it 'should create the db if the argument is sent' do
|
46
|
+
Structure::Grapevine.start(['new', app_name, '--withdb'])
|
47
|
+
FileUtils.cd destination_root
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def app_name
|
54
|
+
'FooApp'
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Create Templates files' do
|
4
|
+
before :each do
|
5
|
+
FileUtils.cd destination_root
|
6
|
+
Structure::Grapevine.new.new('FooApp')
|
7
|
+
FileUtils.cd destination_root + '/foo_app'
|
8
|
+
end
|
9
|
+
|
10
|
+
after :each do
|
11
|
+
FileUtils.cd destination_root
|
12
|
+
FileUtils.remove_dir 'foo_app'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should add a new routes version file' do
|
16
|
+
Structure::Grapevine.new.add_api_version
|
17
|
+
|
18
|
+
File.exists?('app/information/v1/routes.rb').should == true
|
19
|
+
|
20
|
+
file = File.open('app/information/v1/routes.rb', 'r')
|
21
|
+
file.readline.should include "module FooApp"
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grapevine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jaime Andres
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: yard
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: thor
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: json
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: grape
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: i18n
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: roar
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: debugger
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: creates a work environment including grape, roar, rspec, sequel to develop
|
143
|
+
REST architectures
|
144
|
+
email:
|
145
|
+
- andresdavila6@gmail.com
|
146
|
+
executables:
|
147
|
+
- grapevine
|
148
|
+
extensions: []
|
149
|
+
extra_rdoc_files: []
|
150
|
+
files:
|
151
|
+
- .gitignore
|
152
|
+
- .rspec
|
153
|
+
- Gemfile
|
154
|
+
- LICENSE.txt
|
155
|
+
- README.md
|
156
|
+
- Rakefile
|
157
|
+
- bin/grapevine
|
158
|
+
- grapevine.gemspec
|
159
|
+
- lib/grapevine.rb
|
160
|
+
- lib/grapevine/api.rb
|
161
|
+
- lib/grapevine/representer.rb
|
162
|
+
- lib/grapevine/structure/grapevine.rb
|
163
|
+
- lib/grapevine/structure/grapevine_skeleton.rb
|
164
|
+
- lib/grapevine/structure/grapevine_structure/.gitignore.tt
|
165
|
+
- lib/grapevine/structure/grapevine_structure/.rspec.tt
|
166
|
+
- lib/grapevine/structure/grapevine_structure/Gemfile.tt
|
167
|
+
- lib/grapevine/structure/grapevine_structure/README.md.tt
|
168
|
+
- lib/grapevine/structure/grapevine_structure/Rakefile.tt
|
169
|
+
- lib/grapevine/structure/grapevine_structure/app/.gitkeep
|
170
|
+
- lib/grapevine/structure/grapevine_structure/app/context/.gitkeep
|
171
|
+
- lib/grapevine/structure/grapevine_structure/app/data/.gitkeep
|
172
|
+
- lib/grapevine/structure/grapevine_structure/app/decorators/.gitkeep
|
173
|
+
- lib/grapevine/structure/grapevine_structure/app/helpers/.gitkeep
|
174
|
+
- lib/grapevine/structure/grapevine_structure/app/information/.gitkeep
|
175
|
+
- lib/grapevine/structure/grapevine_structure/app/representers/.gitkeep
|
176
|
+
- lib/grapevine/structure/grapevine_structure/app/representers/modules/.gitkeep
|
177
|
+
- lib/grapevine/structure/grapevine_structure/config.ru.tt
|
178
|
+
- lib/grapevine/structure/grapevine_structure/config/application.rb.tt
|
179
|
+
- lib/grapevine/structure/grapevine_structure/config/boot.rb.tt
|
180
|
+
- lib/grapevine/structure/grapevine_structure/config/initializers/.gitkeep
|
181
|
+
- lib/grapevine/structure/grapevine_structure/lib/.gitkeep
|
182
|
+
- lib/grapevine/structure/grapevine_structure/spec/.gitkeep
|
183
|
+
- lib/grapevine/structure/grapevine_structure/spec/initializers/start_server_spec.rb.tt
|
184
|
+
- lib/grapevine/structure/templates/ActiverecordRakefile.tt
|
185
|
+
- lib/grapevine/structure/templates/SequelRakefile.tt
|
186
|
+
- lib/grapevine/structure/templates/activerecord_db_config.rb.tt
|
187
|
+
- lib/grapevine/structure/templates/config.yml.tt
|
188
|
+
- lib/grapevine/structure/templates/db/migrate/.gitkeep
|
189
|
+
- lib/grapevine/structure/templates/db/schema.rb.tt
|
190
|
+
- lib/grapevine/structure/templates/env.sample.tt
|
191
|
+
- lib/grapevine/structure/templates/routes.rb.tt
|
192
|
+
- lib/grapevine/structure/templates/sequel_db_config.rb.tt
|
193
|
+
- lib/grapevine/structure/templates/spec_helper.rb.tt
|
194
|
+
- lib/grapevine/version.rb
|
195
|
+
- spec/grapevine/api_spec.rb
|
196
|
+
- spec/sandbox/.gitkepp
|
197
|
+
- spec/spec_helper.rb
|
198
|
+
- spec/structure/create_app_structure_spec.rb
|
199
|
+
- spec/structure/templates_spec.rb
|
200
|
+
homepage: http://jaimeandres.github.com/grapevine/
|
201
|
+
licenses: []
|
202
|
+
post_install_message:
|
203
|
+
rdoc_options: []
|
204
|
+
require_paths:
|
205
|
+
- lib
|
206
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
207
|
+
none: false
|
208
|
+
requirements:
|
209
|
+
- - ! '>='
|
210
|
+
- !ruby/object:Gem::Version
|
211
|
+
version: '0'
|
212
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
|
+
none: false
|
214
|
+
requirements:
|
215
|
+
- - ! '>='
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
218
|
+
requirements: []
|
219
|
+
rubyforge_project:
|
220
|
+
rubygems_version: 1.8.24
|
221
|
+
signing_key:
|
222
|
+
specification_version: 3
|
223
|
+
summary: REST architecture with DCI in mind thanks to grape
|
224
|
+
test_files:
|
225
|
+
- spec/grapevine/api_spec.rb
|
226
|
+
- spec/sandbox/.gitkepp
|
227
|
+
- spec/spec_helper.rb
|
228
|
+
- spec/structure/create_app_structure_spec.rb
|
229
|
+
- spec/structure/templates_spec.rb
|
230
|
+
has_rdoc:
|