katapult 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Guardfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +122 -0
- data/Rakefile +14 -0
- data/bin/katapult +44 -0
- data/features/binary.feature +48 -0
- data/features/configuration.feature +24 -0
- data/features/katapult.feature +201 -0
- data/features/model.feature +203 -0
- data/features/navigation.feature +80 -0
- data/features/step_definitions/db_steps.rb +8 -0
- data/features/step_definitions/file_steps.rb +14 -0
- data/features/step_definitions/katapult_steps.rb +14 -0
- data/features/step_definitions/rails_steps.rb +44 -0
- data/features/step_definitions/test_steps.rb +7 -0
- data/features/support/env.rb +16 -0
- data/features/wui.feature +319 -0
- data/katapult.gemspec +35 -0
- data/katapult.png +0 -0
- data/lib/generators/katapult/basics/basics_generator.rb +95 -0
- data/lib/generators/katapult/basics/templates/Gemfile +76 -0
- data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application.css.sass +6 -0
- data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_all.css.sass +4 -0
- data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_items.css.sass +11 -0
- data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_layout.css.sass +26 -0
- data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_navigation.css.sass +11 -0
- data/lib/generators/katapult/basics/templates/app/assets/stylesheets/application/blocks/_tools.css.sass +12 -0
- data/lib/generators/katapult/basics/templates/config/database.sample.yml +16 -0
- data/lib/generators/katapult/basics/templates/config/database.yml +13 -0
- data/lib/generators/katapult/basics/templates/config/spring.rb +3 -0
- data/lib/generators/katapult/basics/templates/features/support/env-custom.rb +3 -0
- data/lib/generators/katapult/basics/templates/features/support/paths.rb +47 -0
- data/lib/generators/katapult/cucumber_features/cucumber_features_generator.rb +23 -0
- data/lib/generators/katapult/cucumber_features/templates/feature.feature +59 -0
- data/lib/generators/katapult/haml/haml_generator.rb +90 -0
- data/lib/generators/katapult/haml/templates/_form.html.haml +38 -0
- data/lib/generators/katapult/haml/templates/app/views/layouts/application.html.haml +25 -0
- data/lib/generators/katapult/haml/templates/custom_action.html.haml +5 -0
- data/lib/generators/katapult/haml/templates/edit.html.haml +4 -0
- data/lib/generators/katapult/haml/templates/index.html.haml +29 -0
- data/lib/generators/katapult/haml/templates/new.html.haml +4 -0
- data/lib/generators/katapult/haml/templates/show.html.haml +41 -0
- data/lib/generators/katapult/install/install_generator.rb +14 -0
- data/lib/generators/katapult/install/templates/lib/katapult/application_model.rb +18 -0
- data/lib/generators/katapult/model/model_generator.rb +59 -0
- data/lib/generators/katapult/model/templates/app/models/shared/does_flag.rb +32 -0
- data/lib/generators/katapult/model/templates/model.rb +21 -0
- data/lib/generators/katapult/model_specs/model_specs_generator.rb +51 -0
- data/lib/generators/katapult/model_specs/templates/model_spec.rb +34 -0
- data/lib/generators/katapult/navigation/navigation_generator.rb +25 -0
- data/lib/generators/katapult/navigation/templates/app/models/navigation.rb +12 -0
- data/lib/generators/katapult/transform/transform_generator.rb +47 -0
- data/lib/generators/katapult/w_u_i/templates/_route.rb +13 -0
- data/lib/generators/katapult/w_u_i/templates/controller.rb +106 -0
- data/lib/generators/katapult/w_u_i/w_u_i_generator.rb +57 -0
- data/lib/katapult.rb +5 -0
- data/lib/katapult/action.rb +44 -0
- data/lib/katapult/application_model.rb +45 -0
- data/lib/katapult/attribute.rb +83 -0
- data/lib/katapult/element.rb +72 -0
- data/lib/katapult/generator.rb +28 -0
- data/lib/katapult/model.rb +33 -0
- data/lib/katapult/navigation.rb +22 -0
- data/lib/katapult/parser.rb +39 -0
- data/lib/katapult/util.rb +16 -0
- data/lib/katapult/version.rb +3 -0
- data/lib/katapult/wui.rb +77 -0
- data/script/console +16 -0
- data/spec/action_spec.rb +44 -0
- data/spec/attribute_spec.rb +48 -0
- data/spec/model_spec.rb +18 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/util_spec.rb +23 -0
- data/spec/wui_spec.rb +49 -0
- metadata +253 -0
data/katapult.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'katapult/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'katapult'
|
8
|
+
spec.version = Katapult::VERSION
|
9
|
+
spec.authors = ['Dominik Schöler']
|
10
|
+
spec.email = ['dominik.schoeler@makandra.de']
|
11
|
+
spec.summary = %q{Kickstart Rails development}
|
12
|
+
spec.description = %q{Katapult is a framework for generating base code}
|
13
|
+
spec.homepage = 'https://github.com/makandra/katapult'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 2.0'
|
22
|
+
|
23
|
+
spec.add_runtime_dependency 'rails'
|
24
|
+
spec.add_runtime_dependency 'spring' # speed-up
|
25
|
+
|
26
|
+
# Development
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
28
|
+
spec.add_development_dependency 'rake'
|
29
|
+
spec.add_development_dependency 'pry'
|
30
|
+
|
31
|
+
# Testing
|
32
|
+
spec.add_development_dependency 'aruba'
|
33
|
+
spec.add_development_dependency 'guard-cucumber'
|
34
|
+
spec.add_development_dependency 'rspec'
|
35
|
+
end
|
data/katapult.png
ADDED
Binary file
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Generates model-independent application basics (see method names).
|
2
|
+
|
3
|
+
module Katapult
|
4
|
+
module Generators
|
5
|
+
class BasicsGenerator < Rails::Generators::Base
|
6
|
+
|
7
|
+
SKIP_GEMS = %w(sass-rails coffee-rails turbolinks sdoc uglifier)
|
8
|
+
|
9
|
+
desc 'Generate basics like test directories and gems'
|
10
|
+
source_root File.expand_path('../templates', __FILE__)
|
11
|
+
|
12
|
+
|
13
|
+
def write_database_ymls
|
14
|
+
template 'config/database.yml', force: true
|
15
|
+
template 'config/database.sample.yml'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Overwrite Gemfile with the template, but transfer all gems that are not
|
19
|
+
# skipped (see SKIP_GEMS).
|
20
|
+
def enhance_gemfile
|
21
|
+
gem_lines = File.readlines('Gemfile').select{ |line| line =~ /^gem/ }
|
22
|
+
@original_gems = gem_lines.reject do |line|
|
23
|
+
line =~ /'(#{ SKIP_GEMS.join '|' })'/
|
24
|
+
end
|
25
|
+
|
26
|
+
template 'Gemfile', force: true
|
27
|
+
end
|
28
|
+
|
29
|
+
def bundle_install
|
30
|
+
bundle 'install'
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_turbolinks_js
|
34
|
+
gsub_file 'app/assets/javascripts/application.js', "//= require turbolinks\n", ''
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup_spring
|
38
|
+
bundle 'exec spring binstub --all'
|
39
|
+
template 'config/spring.rb'
|
40
|
+
run 'spring stop' # reload
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_modularity_load_paths
|
44
|
+
# This results in correct formatting :)
|
45
|
+
application <<-'LOAD_PATHS'
|
46
|
+
config.autoload_paths << "#{Rails.root}/app/controllers/shared"
|
47
|
+
config.autoload_paths << "#{Rails.root}/app/models/shared"
|
48
|
+
config.autoload_paths << "#{Rails.root}/app/util"
|
49
|
+
config.autoload_paths << "#{Rails.root}/app/util/shared"
|
50
|
+
LOAD_PATHS
|
51
|
+
end
|
52
|
+
|
53
|
+
def install_cucumber
|
54
|
+
generate 'cucumber:install'
|
55
|
+
|
56
|
+
template 'features/support/paths.rb'
|
57
|
+
template 'features/support/env-custom.rb'
|
58
|
+
end
|
59
|
+
|
60
|
+
def install_rspec
|
61
|
+
generate 'rspec:install'
|
62
|
+
|
63
|
+
# Do not show Ruby warnings in RSpec runs.
|
64
|
+
gsub_file '.rspec', "--warnings\n", ''
|
65
|
+
|
66
|
+
inject_into_file 'spec/rails_helper.rb', after: "require 'rspec/rails'\n" do
|
67
|
+
"require 'shoulda/matchers'\n"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def install_styles
|
72
|
+
remove_file 'app/assets/stylesheets/application.css'
|
73
|
+
directory 'app/assets/stylesheets', force: true
|
74
|
+
end
|
75
|
+
|
76
|
+
# def install_capistrano
|
77
|
+
# capify!
|
78
|
+
# template 'config/deploy.rb'
|
79
|
+
# end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def app_name
|
84
|
+
File.basename(Dir.pwd)
|
85
|
+
end
|
86
|
+
|
87
|
+
def bundle(command)
|
88
|
+
Bundler.with_clean_env do
|
89
|
+
run 'bundle ' + command
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# from original Gemfile
|
4
|
+
<%= @original_gems.join %>
|
5
|
+
|
6
|
+
# engines
|
7
|
+
gem 'haml-rails'
|
8
|
+
|
9
|
+
# internal
|
10
|
+
gem 'exception_notification'
|
11
|
+
gem 'breach-mitigation-rails'
|
12
|
+
|
13
|
+
# better coding
|
14
|
+
gem 'modularity'
|
15
|
+
gem 'edge_rider'
|
16
|
+
gem 'andand'
|
17
|
+
|
18
|
+
# models
|
19
|
+
gem 'has_defaults'
|
20
|
+
gem 'assignable_values'
|
21
|
+
|
22
|
+
# gem 'carrierwave'
|
23
|
+
# gem 'mini_magick'
|
24
|
+
|
25
|
+
# gem 'spreadsheet'
|
26
|
+
# gem 'vcard'
|
27
|
+
|
28
|
+
# views
|
29
|
+
# gem 'simple_form'
|
30
|
+
# gem 'nested_form'
|
31
|
+
gem 'will_paginate'
|
32
|
+
gem 'makandra-navy', require: 'navy'
|
33
|
+
|
34
|
+
# assets
|
35
|
+
gem 'bootstrap-sass'
|
36
|
+
gem 'sass-rails'
|
37
|
+
gem 'autoprefixer-rails'
|
38
|
+
gem 'coffee-rails'
|
39
|
+
gem 'uglifier'
|
40
|
+
gem 'compass-rails'
|
41
|
+
gem 'compass-rgbapng'
|
42
|
+
|
43
|
+
group :development do
|
44
|
+
gem 'query_diet'
|
45
|
+
gem 'better_errors'
|
46
|
+
gem 'binding_of_caller'
|
47
|
+
gem 'thin'
|
48
|
+
|
49
|
+
gem 'guard-livereload', require: false
|
50
|
+
gem 'rack-livereload'
|
51
|
+
gem 'spring-commands-rspec'
|
52
|
+
gem 'spring-commands-cucumber'
|
53
|
+
end
|
54
|
+
|
55
|
+
group :development, :test do
|
56
|
+
gem 'byebug'
|
57
|
+
gem 'factory_girl_rails'
|
58
|
+
gem 'rspec-rails'
|
59
|
+
end
|
60
|
+
|
61
|
+
group :test do
|
62
|
+
gem 'parallel_tests'
|
63
|
+
gem 'database_cleaner'
|
64
|
+
gem 'timecop'
|
65
|
+
gem 'launchy'
|
66
|
+
|
67
|
+
gem 'capybara'
|
68
|
+
gem 'cucumber-rails', require: false
|
69
|
+
gem 'cucumber_factory'
|
70
|
+
gem 'cucumber_spinner'
|
71
|
+
gem 'selenium-webdriver'
|
72
|
+
gem 'spreewald'
|
73
|
+
|
74
|
+
gem 'rspec_candy'
|
75
|
+
gem 'shoulda-matchers', require: false
|
76
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
@import compass/css3/box-shadow
|
2
|
+
@import bootstrap/variables
|
3
|
+
|
4
|
+
.layout
|
5
|
+
margin: 100px auto
|
6
|
+
width: 800px
|
7
|
+
|
8
|
+
background-color: white
|
9
|
+
+single-box-shadow
|
10
|
+
|
11
|
+
.layout__head
|
12
|
+
padding: 10px 35px
|
13
|
+
|
14
|
+
color: #fff
|
15
|
+
background-color: $brand-primary
|
16
|
+
|
17
|
+
.layout__main
|
18
|
+
padding: 20px 35px
|
19
|
+
|
20
|
+
.layout__tail
|
21
|
+
padding: 10px 35px
|
22
|
+
|
23
|
+
color: $gray-light
|
24
|
+
background-color: $gray-lighter
|
25
|
+
border-top: 1px solid darken($gray-lighter, 10%)
|
26
|
+
font-size: $font-size-small
|
@@ -0,0 +1,16 @@
|
|
1
|
+
common: &common
|
2
|
+
adapter: mysql2
|
3
|
+
encoding: utf8
|
4
|
+
username: root
|
5
|
+
password:
|
6
|
+
|
7
|
+
development:
|
8
|
+
<<: *common
|
9
|
+
database: <%= app_name %>_development
|
10
|
+
|
11
|
+
test: &test
|
12
|
+
<<: *common
|
13
|
+
database: <%= app_name %>_test<%%= ENV['TEST_ENV_NUMBER'] %>
|
14
|
+
|
15
|
+
cucumber:
|
16
|
+
<<: *test
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module NavigationHelpers
|
2
|
+
|
3
|
+
def path_to(page_name)
|
4
|
+
case page_name
|
5
|
+
|
6
|
+
when /^the list of (.*?)$/
|
7
|
+
models_prose = $1
|
8
|
+
route = "#{model_prose_to_route_segment(models_prose)}_path"
|
9
|
+
send(route)
|
10
|
+
|
11
|
+
when /^the (page|form) for the (.*?) above$/
|
12
|
+
action_prose, model_prose = $1, $2
|
13
|
+
route = "#{action_prose == 'form' ? 'edit_' : ''}#{model_prose_to_route_segment(model_prose)}_path"
|
14
|
+
model = model_prose.classify.constantize
|
15
|
+
send(route, model.last)
|
16
|
+
|
17
|
+
when /^the (page|form) for the (.*?) "(.*?)"$/
|
18
|
+
action_prose, model_prose, identifier = $1, $2, $3
|
19
|
+
path_to_show_or_edit(action_prose, model_prose, identifier)
|
20
|
+
|
21
|
+
when /^the (.*?) (page|form) for "(.*?)"$/
|
22
|
+
model_prose, action_prose, identifier = $1, $2, $3
|
23
|
+
path_to_show_or_edit(action_prose, model_prose, identifier)
|
24
|
+
|
25
|
+
when /^the (.*?) form$/
|
26
|
+
model_prose = $1
|
27
|
+
route = "new_#{model_prose_to_route_segment(model_prose)}_path"
|
28
|
+
send(route)
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def path_to_show_or_edit(action_prose, model_prose, identifier)
|
36
|
+
model = model_prose.classify.constantize
|
37
|
+
route = "#{action_prose == 'form' ? 'edit_' : ''}#{model_prose_to_route_segment(model_prose)}_path"
|
38
|
+
send(route, model.find_by_anything!(identifier))
|
39
|
+
end
|
40
|
+
|
41
|
+
def model_prose_to_route_segment(model_prose)
|
42
|
+
model_prose.gsub(/[\ \/]/, '_')
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
World(NavigationHelpers)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'katapult/generator'
|
2
|
+
|
3
|
+
module Katapult
|
4
|
+
module Generators
|
5
|
+
class CucumberFeaturesGenerator < Katapult::Generator
|
6
|
+
|
7
|
+
desc 'Generate Cucumber features for CRUD'
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
|
11
|
+
def create_crud_feature
|
12
|
+
template 'feature.feature', "features/#{model.name(:variables)}.feature"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def model
|
18
|
+
@element
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
Feature: <%= model.name(:human_plural).titleize %>
|
2
|
+
|
3
|
+
Scenario: CRUD <%= model.name(:human_plural) %>
|
4
|
+
Given I am on the list of <%= model.name(:variables) %>
|
5
|
+
|
6
|
+
# create
|
7
|
+
When I follow "Add <%= model.name(:variable) %>"
|
8
|
+
<% model.attrs.each do |attr| -%>
|
9
|
+
<%- if attr.assignable_values -%>
|
10
|
+
And I select "<%= attr.test_value %>" from "<%= attr.name.humanize %>"
|
11
|
+
<%- else -%>
|
12
|
+
<%- case attr.type -%>
|
13
|
+
<%- when :string, :email, :url, :integer, :money, :text, :markdown, :datetime -%>
|
14
|
+
And I fill in "<%= attr.name.humanize %>" with "<%= attr.test_value %>"
|
15
|
+
<%- when :flag -%>
|
16
|
+
And I check "<%= attr.name.humanize %>"
|
17
|
+
<%- end -%>
|
18
|
+
<%- end -%>
|
19
|
+
<% end -%>
|
20
|
+
And I press "Save"
|
21
|
+
|
22
|
+
# read
|
23
|
+
Then I should be on the page for the <%= model.name(:variable) %> above
|
24
|
+
<% model.attrs.each do |attr| -%>
|
25
|
+
<%- case attr.type -%>
|
26
|
+
<%- when :string, :email, :url, :integer, :money, :text, :markdown -%>
|
27
|
+
And I should see "<%= attr.test_value %>"
|
28
|
+
<%- when :flag -%>
|
29
|
+
And I should see "<%= attr.name.humanize %> Yes"
|
30
|
+
<%- when :datetime -%>
|
31
|
+
And I should see "<%= I18n.localize(attr.test_value) %>"
|
32
|
+
<%- end -%>
|
33
|
+
<% end -%>
|
34
|
+
|
35
|
+
# update
|
36
|
+
When I follow "Edit"
|
37
|
+
Then I should be on the form for the <%= model.name(:variable) %> above
|
38
|
+
<% model.attrs.each do |attr| -%>
|
39
|
+
<%- if attr.assignable_values -%>
|
40
|
+
And "<%= attr.test_value %>" should be selected for "<%= attr.name.humanize %>"
|
41
|
+
<%- else -%>
|
42
|
+
<%- case attr.type -%>
|
43
|
+
<%- when :string, :email, :url, :integer, :money, :text, :markdown, :datetime -%>
|
44
|
+
And the "<%= attr.name.humanize %>" field should contain "<%= attr.test_value %>"
|
45
|
+
<%- when :flag -%>
|
46
|
+
And the "<%= attr.name.humanize %>" checkbox should be checked
|
47
|
+
<%- end -%>
|
48
|
+
<%- end -%>
|
49
|
+
<% end -%>
|
50
|
+
|
51
|
+
<% if model.label_attr # do not crash when the model has no label attr -%>
|
52
|
+
# destroy
|
53
|
+
When I go to the list of <%= model.name(:variables) %>
|
54
|
+
Then I should see "<%= model.label_attr.test_value %>"
|
55
|
+
|
56
|
+
When I follow "Destroy"
|
57
|
+
Then I should be on the list of <%= model.name(:variables) %>
|
58
|
+
But I should not see "<%= model.label_attr.test_value %>"
|
59
|
+
<% end -%>
|