katapult 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +57 -9
- data/bin/katapult +7 -3
- data/features/application_model.feature +4 -1
- data/features/authenticate.feature +1 -18
- data/features/basics.feature +1 -0
- data/features/binary.feature +5 -7
- data/features/model.feature +42 -3
- data/features/step_definitions/rails_steps.rb +1 -1
- data/features/web_ui.feature +17 -5
- data/lib/generators/katapult/app_model/templates/lib/katapult/application_model.rb +3 -0
- data/lib/generators/katapult/basics/basics_generator.rb +3 -8
- data/lib/generators/katapult/basics/templates/README.md.tt +33 -0
- data/lib/generators/katapult/basics/templates/features/support/paths.rb +1 -1
- data/lib/generators/katapult/clearance/clearance_generator.rb +6 -2
- data/lib/generators/katapult/clearance/templates/config/initializers/clearance.rb +1 -0
- data/lib/generators/katapult/cucumber_features/cucumber_features_generator.rb +10 -0
- data/lib/generators/katapult/cucumber_features/templates/feature.feature +4 -3
- data/lib/generators/katapult/model/model_generator.rb +15 -0
- data/lib/generators/katapult/model/templates/model.rb +13 -3
- data/lib/generators/katapult/model_specs/model_specs_generator.rb +1 -1
- data/lib/generators/katapult/model_specs/templates/model_spec.rb +1 -1
- data/lib/generators/katapult/transform/transform_generator.rb +4 -7
- data/lib/generators/katapult/views/templates/_form.html.haml +16 -13
- data/lib/generators/katapult/views/templates/show.html.haml +2 -0
- data/lib/katapult/application_model.rb +68 -19
- data/lib/katapult/element.rb +13 -18
- data/lib/katapult/{action.rb → elements/action.rb} +0 -0
- data/lib/katapult/elements/association.rb +35 -0
- data/lib/katapult/{attribute.rb → elements/attribute.rb} +14 -5
- data/lib/katapult/{authentication.rb → elements/authentication.rb} +2 -5
- data/lib/katapult/elements/model.rb +76 -0
- data/lib/katapult/{navigation.rb → elements/navigation.rb} +0 -0
- data/lib/katapult/{web_ui.rb → elements/web_ui.rb} +2 -12
- data/lib/katapult/generator.rb +2 -2
- data/lib/katapult/{binary_util.rb → support/binary_util.rb} +2 -1
- data/lib/katapult/{generator_goodies.rb → support/generator_goodies.rb} +9 -2
- data/lib/katapult/version.rb +1 -1
- data/script/console +5 -2
- data/script/update +1 -1
- data/spec/action_spec.rb +1 -1
- data/spec/application_model_spec.rb +26 -0
- data/spec/association_spec.rb +12 -0
- data/spec/attribute_spec.rb +35 -1
- data/spec/model_spec.rb +5 -2
- data/spec/util_spec.rb +1 -1
- data/spec/web_ui_spec.rb +11 -33
- metadata +17 -13
- data/lib/katapult/model.rb +0 -45
- data/lib/katapult/parser.rb +0 -53
- data/spec/parser_spec.rb +0 -26
@@ -1,21 +1,31 @@
|
|
1
|
-
class <%= class_name %> <
|
1
|
+
class <%= class_name %> < ApplicationRecord
|
2
|
+
|
2
3
|
<%- flag_attrs.each do |attr| -%>
|
3
4
|
include DoesFlag[<%= attr.name(:symbol) %>, default: <%= attr.default %>]
|
4
5
|
<%- end -%>
|
6
|
+
<% has_manys.each do |model| -%>
|
7
|
+
has_many <%= model.name(:symbols) %>
|
8
|
+
<% end -%>
|
9
|
+
<% belongs_tos.each do |model| -%>
|
10
|
+
belongs_to <%= model.name(:symbol) %>, optional: true
|
11
|
+
<% end -%>
|
5
12
|
<%- if defaults.any? -%>
|
13
|
+
|
6
14
|
has_defaults(<%= defaults %>)
|
7
15
|
<%- end -%>
|
8
16
|
<%- model.attrs.select(&:assignable_values).each do |attr| -%>
|
9
|
-
|
17
|
+
|
18
|
+
assignable_values_for :<%= attr.name(:variable).sub /_id$/, '' %>, <%= attr.options.slice(:allow_blank, :default) %> do
|
10
19
|
<%= attr.assignable_values %>
|
11
20
|
end
|
12
21
|
<%- end -%>
|
13
22
|
|
14
23
|
def to_s
|
15
|
-
<% if model.label_attr -%>
|
24
|
+
<% if model.label_attr? -%>
|
16
25
|
<%= model.label_attr.name %>.to_s
|
17
26
|
<% else -%>
|
18
27
|
"<%= model.name %>##{id}"
|
19
28
|
<% end -%>
|
20
29
|
end
|
30
|
+
|
21
31
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
describe <%= model.name :class %> do
|
2
2
|
|
3
3
|
describe '#to_s' do
|
4
|
-
<%- if model.label_attr -%>
|
4
|
+
<%- if model.label_attr? -%>
|
5
5
|
it 'returns the #<%= model.label_attr.name %> attribute' do
|
6
6
|
subject.<%= model.label_attr.name %> = <%= model.label_attr.test_value.inspect %>
|
7
7
|
expect(subject.to_s).to eq(<%= model.label_attr.test_value.to_s.inspect %>)
|
@@ -1,12 +1,9 @@
|
|
1
1
|
# Generate files and directories from an application model file. Afterwards do
|
2
2
|
# any setup left necessary (e.g. updating the database).
|
3
3
|
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require 'katapult/parser'
|
9
|
-
require 'katapult/generator_goodies'
|
4
|
+
# A normal #require would load the application model from the generated app
|
5
|
+
require_relative '../../../katapult/application_model'
|
6
|
+
require 'katapult/support/generator_goodies'
|
10
7
|
|
11
8
|
module Katapult
|
12
9
|
class TransformGenerator < Rails::Generators::Base
|
@@ -20,7 +17,7 @@ module Katapult
|
|
20
17
|
def transform_application_model
|
21
18
|
say_status :parse, path
|
22
19
|
application_model = File.read(path)
|
23
|
-
@app_model = Katapult::
|
20
|
+
@app_model = Katapult::ApplicationModel.parse(application_model, path)
|
24
21
|
|
25
22
|
say_status :render, "into #{app_name}"
|
26
23
|
@app_model.render
|
@@ -4,36 +4,39 @@
|
|
4
4
|
<% web_ui.model.editable_attrs.each do |attribute| -%>
|
5
5
|
.form-group
|
6
6
|
= form.label <%= attribute.name(:symbol) %>
|
7
|
-
|
7
|
+
<% if attribute.type == :foreign_key -%>
|
8
|
+
= form.collection_select <%= attribute.name(:symbol) %>, form.object.assignable_<%= attribute.name(:variables).sub(/_ids$/, 's') %>,
|
9
|
+
:id, <%= attribute.associated_model.label_attr.name(:symbol) %>, { include_blank: true }, class: 'form-control'
|
10
|
+
<% elsif attribute.assignable_values -%>
|
8
11
|
= form.select <%= attribute.name(:symbol) %>, form.object.assignable_<%= attribute.name(:variables) %>
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
<% else -%>
|
13
|
+
<%- case attribute.type -%>
|
14
|
+
<%- when :string -%>
|
12
15
|
= form.text_field <%= attribute.name(:symbol) %>, class: 'form-control'
|
13
|
-
|
16
|
+
<%- when :email -%>
|
14
17
|
= form.email_field <%= attribute.name(:symbol) %>, class: 'form-control'
|
15
|
-
|
18
|
+
<%- when :password -%>
|
16
19
|
= form.password_field <%= attribute.name(:symbol) %>, class: 'form-control',
|
17
20
|
autocomplete: 'new-password'
|
18
|
-
|
21
|
+
<%- when :url -%>
|
19
22
|
= form.url_field <%= attribute.name(:symbol) %>, class: 'form-control'
|
20
|
-
|
23
|
+
<%- when :integer -%>
|
21
24
|
= form.number_field <%= attribute.name(:symbol) %>, class: 'form-control'
|
22
|
-
|
25
|
+
<%- when :money -%>
|
23
26
|
.input-group
|
24
27
|
= form.number_field <%= attribute.name(:symbol) %>, class: 'form-control'
|
25
28
|
.input-group-addon
|
26
29
|
€
|
27
|
-
|
30
|
+
<%- when :text -%>
|
28
31
|
= form.text_area <%= attribute.name(:symbol) %>, rows: 5, class: 'form-control'
|
29
|
-
|
32
|
+
<%- when :flag -%>
|
30
33
|
.checkbox
|
31
34
|
= form.label <%= attribute.name(:symbol) %> do
|
32
35
|
= form.check_box <%= attribute.name(:symbol) %>
|
33
|
-
|
36
|
+
<%- when :datetime -%>
|
34
37
|
= form.date_field <%= attribute.name(:symbol) %>, class: 'form-control'
|
35
|
-
<%- end -%>
|
36
38
|
<%- end -%>
|
39
|
+
<% end -%>
|
37
40
|
<% end -%>
|
38
41
|
|
39
42
|
.action-bar
|
@@ -1,52 +1,101 @@
|
|
1
|
-
#
|
1
|
+
# Root of the internal representation of an application model file
|
2
|
+
|
3
|
+
require 'katapult/elements/model'
|
4
|
+
require 'katapult/elements/web_ui'
|
5
|
+
require 'katapult/elements/navigation'
|
6
|
+
require 'katapult/elements/authentication'
|
7
|
+
require 'katapult/elements/association'
|
2
8
|
|
3
9
|
module Katapult
|
4
10
|
class ApplicationModel
|
5
11
|
|
6
|
-
|
12
|
+
NotFound = Class.new(StandardError)
|
13
|
+
|
14
|
+
attr_reader :models, :web_uis, :navigation, :authentication, :associations
|
15
|
+
|
16
|
+
def self.parse(application_model_string, path_to_model = '')
|
17
|
+
new.tap do |model|
|
18
|
+
model.instance_eval application_model_string, path_to_model
|
19
|
+
end
|
20
|
+
end
|
7
21
|
|
8
22
|
def initialize
|
9
23
|
@models = []
|
24
|
+
@associations = []
|
10
25
|
@web_uis = []
|
11
26
|
end
|
12
27
|
|
13
|
-
|
14
|
-
|
15
|
-
|
28
|
+
# DSL
|
29
|
+
def model(name, &block)
|
30
|
+
models << Model.new(name, application_model: self, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
# DSL
|
34
|
+
def web_ui(name, options = {}, &block)
|
35
|
+
options[:application_model] = self
|
36
|
+
web_uis << WebUI.new(name, options, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# DSL
|
40
|
+
def navigation(name = :main)
|
41
|
+
@navigation = Navigation.new(name, application_model: self)
|
42
|
+
end
|
43
|
+
|
44
|
+
# DSL
|
45
|
+
def authenticate(user_model_name, system_email:)
|
46
|
+
@authentication = Authentication.new(user_model_name,
|
47
|
+
system_email: system_email, application_model: self)
|
16
48
|
end
|
17
49
|
|
18
|
-
|
19
|
-
|
50
|
+
# DSL
|
51
|
+
def crud(name, &block)
|
52
|
+
model name, &block
|
53
|
+
web_ui name, &:crud
|
20
54
|
end
|
21
55
|
|
22
|
-
|
23
|
-
|
24
|
-
|
56
|
+
|
57
|
+
def association(name, options = {})
|
58
|
+
options[:application_model] = self
|
59
|
+
associations << Association.new(name, options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_model!(name)
|
63
|
+
models.find { |m| m.name == name } or raise NotFound,
|
64
|
+
"Could not find a model named #{ name }"
|
25
65
|
end
|
26
66
|
|
27
67
|
def get_web_ui(name)
|
28
68
|
web_uis.find { |w| w.name == name }
|
29
69
|
end
|
30
70
|
|
31
|
-
|
32
|
-
|
33
|
-
|
71
|
+
# Returns all models that `model_name` belongs_to
|
72
|
+
def get_belongs_tos_for(model_name)
|
73
|
+
associations.select { |a| a.name == model_name }.map(&:belongs_to_model)
|
34
74
|
end
|
35
75
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@authentication = auth
|
76
|
+
# Returns all models that `model_name` has_many of
|
77
|
+
def get_has_manys_for(model_name)
|
78
|
+
associations.select { |a| a.belongs_to == model_name }.map(&:model)
|
40
79
|
end
|
41
80
|
|
42
|
-
# ---
|
43
|
-
|
44
81
|
def render
|
82
|
+
prepare_render
|
83
|
+
|
45
84
|
models.each &:render
|
46
85
|
web_uis.each &:render
|
47
86
|
navigation.render if navigation
|
48
87
|
authentication.render if authentication
|
49
88
|
end
|
50
89
|
|
90
|
+
private
|
91
|
+
|
92
|
+
def prepare_render
|
93
|
+
authentication &.ensure_user_model_attributes_present
|
94
|
+
models.each do |model|
|
95
|
+
belongs_tos = get_belongs_tos_for(model.name)
|
96
|
+
model.add_foreign_key_attrs(belongs_tos)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
51
100
|
end
|
52
101
|
end
|
data/lib/katapult/element.rb
CHANGED
@@ -10,10 +10,9 @@ module Katapult
|
|
10
10
|
UnknownOptionError = Class.new(StandardError)
|
11
11
|
UnknownFormattingError = Class.new(StandardError)
|
12
12
|
|
13
|
-
attr_accessor :name, :options
|
14
|
-
attr_reader :application_model
|
13
|
+
attr_accessor :name, :options, :application_model
|
15
14
|
|
16
|
-
#
|
15
|
+
# Use #options for DSL/API, attr_accessor for internal attributes
|
17
16
|
class << self
|
18
17
|
alias_method :options, :attr_accessor
|
19
18
|
end
|
@@ -28,26 +27,22 @@ module Katapult
|
|
28
27
|
yield(self) if block_given?
|
29
28
|
end
|
30
29
|
|
31
|
-
def set_application_model(app_model)
|
32
|
-
@application_model = app_model
|
33
|
-
end
|
34
|
-
|
35
30
|
def name(kind = nil)
|
36
31
|
machine_name = @name.underscore
|
37
32
|
human_name = machine_name.humanize.downcase
|
38
33
|
|
39
34
|
case kind.to_s
|
40
|
-
when '' then @name
|
41
|
-
when 'symbol' then ":#{machine_name}"
|
42
|
-
when 'symbols' then ":#{machine_name.pluralize}"
|
43
|
-
when 'variable' then machine_name
|
44
|
-
when 'variables' then machine_name.pluralize
|
45
|
-
when 'ivar' then "@#{machine_name}"
|
46
|
-
when 'ivars' then "@#{machine_name.pluralize}"
|
47
|
-
when 'human' then human_name
|
48
|
-
when 'humans' then human_name.pluralize
|
49
|
-
when 'class' then machine_name.classify
|
50
|
-
when 'classes' then machine_name.classify.pluralize
|
35
|
+
when '' then @name ## Example
|
36
|
+
when 'symbol' then ":#{machine_name}" # :user_task
|
37
|
+
when 'symbols' then ":#{machine_name.pluralize}" # :user_tasks
|
38
|
+
when 'variable' then machine_name # user_task
|
39
|
+
when 'variables' then machine_name.pluralize # user_tasks
|
40
|
+
when 'ivar' then "@#{machine_name}" # @user_task
|
41
|
+
when 'ivars' then "@#{machine_name.pluralize}" # @user_tasks
|
42
|
+
when 'human' then human_name # user task
|
43
|
+
when 'humans' then human_name.pluralize # user tasks
|
44
|
+
when 'class' then machine_name.classify # UserTask
|
45
|
+
when 'classes' then machine_name.classify.pluralize # UserTasks
|
51
46
|
else raise UnknownFormattingError, "Unknown name formatting: #{ kind.inspect }"
|
52
47
|
end
|
53
48
|
end
|
File without changes
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Models an association between models
|
2
|
+
|
3
|
+
require 'katapult/element'
|
4
|
+
|
5
|
+
module Katapult
|
6
|
+
class Association < Element
|
7
|
+
|
8
|
+
IncompleteAssociationError = Class.new(StandardError)
|
9
|
+
|
10
|
+
options :belongs_to
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
validate!
|
15
|
+
|
16
|
+
self.belongs_to = belongs_to.to_s # Normalize
|
17
|
+
end
|
18
|
+
|
19
|
+
def model
|
20
|
+
application_model.get_model! name
|
21
|
+
end
|
22
|
+
|
23
|
+
def belongs_to_model
|
24
|
+
application_model.get_model! belongs_to
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
belongs_to.present? or raise IncompleteAssociationError,
|
31
|
+
'Missing :belongs_to option'
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -9,10 +9,12 @@ module Katapult
|
|
9
9
|
class Attribute < Element
|
10
10
|
|
11
11
|
options :type, :default, :assignable_values, :allow_blank, :skip_db
|
12
|
+
attr_accessor :model, :associated_model
|
12
13
|
|
13
14
|
UnknownTypeError = Class.new(StandardError)
|
14
15
|
MissingOptionError = Class.new(StandardError)
|
15
|
-
TYPES = %i
|
16
|
+
TYPES = %i[string email password url integer money text flag datetime json
|
17
|
+
plain_json foreign_key]
|
16
18
|
|
17
19
|
def initialize(*args)
|
18
20
|
super
|
@@ -21,13 +23,13 @@ module Katapult
|
|
21
23
|
self.type ||= :password if name.to_s =~ /password/
|
22
24
|
self.type ||= :string
|
23
25
|
|
24
|
-
validate
|
26
|
+
validate!
|
25
27
|
end
|
26
28
|
|
27
29
|
delegate :flag?, to: :type_inquiry
|
28
30
|
|
29
31
|
def has_defaults?
|
30
|
-
default and not [flag?, assignable_values].any?
|
32
|
+
!default.nil? and not [flag?, assignable_values].any?
|
31
33
|
end
|
32
34
|
|
33
35
|
def for_migration
|
@@ -37,13 +39,16 @@ module Katapult
|
|
37
39
|
when :money then 'decimal{10,2}' # {precision,scale} = total digits, decimal places
|
38
40
|
when :json then 'jsonb' # Indexable JSON
|
39
41
|
when :plain_json then 'json' # Only use this if you need to
|
42
|
+
when :foreign_key then 'integer'
|
40
43
|
else type end
|
41
44
|
|
42
45
|
"#{name}:#{db_type}"
|
43
46
|
end
|
44
47
|
|
45
48
|
def test_value
|
46
|
-
if
|
49
|
+
if type == :foreign_key
|
50
|
+
associated_model.label_attr.test_value
|
51
|
+
elsif assignable_values
|
47
52
|
assignable_values.first
|
48
53
|
|
49
54
|
else
|
@@ -62,13 +67,17 @@ module Katapult
|
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
70
|
+
def assignable_values_as_list?
|
71
|
+
assignable_values.try(:to_a).present?
|
72
|
+
end
|
73
|
+
|
65
74
|
private
|
66
75
|
|
67
76
|
def type_inquiry
|
68
77
|
@type.to_s.inquiry
|
69
78
|
end
|
70
79
|
|
71
|
-
def validate
|
80
|
+
def validate!
|
72
81
|
TYPES.include?(type) or raise UnknownTypeError,
|
73
82
|
"Attribute type :#{type} is not supported. Use one of #{TYPES.inspect}."
|
74
83
|
|
@@ -3,14 +3,11 @@ require 'generators/katapult/clearance/clearance_generator'
|
|
3
3
|
module Katapult
|
4
4
|
class Authentication < Element
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
# attr name: The user model name
|
6
|
+
# @attr name: The user model name
|
9
7
|
attr_accessor :system_email
|
10
8
|
|
11
9
|
def ensure_user_model_attributes_present
|
12
|
-
user_model = application_model.get_model(name)
|
13
|
-
"Could not find a model named #{ name }"
|
10
|
+
user_model = application_model.get_model!(name)
|
14
11
|
user_attrs = user_model.attrs.map(&:name)
|
15
12
|
|
16
13
|
user_model.attr(:email) unless user_attrs.include?('email')
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Models a Rails model
|
2
|
+
|
3
|
+
require 'katapult/element'
|
4
|
+
require 'katapult/elements/attribute'
|
5
|
+
require 'generators/katapult/model/model_generator'
|
6
|
+
|
7
|
+
module Katapult
|
8
|
+
class Model < Element
|
9
|
+
|
10
|
+
UnknownAttributeError = Class.new(StandardError)
|
11
|
+
MissingLabelAttributeError = Class.new(StandardError)
|
12
|
+
|
13
|
+
attr_accessor :attrs, :belongs_tos, :has_manys
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
self.attrs = []
|
17
|
+
self._belongs_tos = []
|
18
|
+
self.belongs_tos = []
|
19
|
+
self.has_manys = []
|
20
|
+
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# DSL
|
25
|
+
def attr(attr_name, options = {})
|
26
|
+
options[:model] = self
|
27
|
+
attrs << Attribute.new(attr_name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
# DSL
|
31
|
+
def belongs_to(model_name)
|
32
|
+
application_model.association name, belongs_to: model_name
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def label_attr
|
37
|
+
renderable_attrs.first.presence or raise MissingLabelAttributeError
|
38
|
+
end
|
39
|
+
|
40
|
+
def label_attr?
|
41
|
+
label_attr.present?
|
42
|
+
rescue MissingLabelAttributeError
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def db_fields
|
47
|
+
attrs.reject(&:skip_db)
|
48
|
+
end
|
49
|
+
|
50
|
+
def renderable_attrs
|
51
|
+
attrs.reject { |a| %w[plain_json json password].include? a.type.to_s }
|
52
|
+
end
|
53
|
+
|
54
|
+
def editable_attrs
|
55
|
+
attrs.reject { |a| %w[plain_json json].include? a.type.to_s }
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_foreign_key_attrs(belongs_tos)
|
59
|
+
belongs_tos.each do |other_model|
|
60
|
+
attr "#{ other_model.name :variable }_id", type: :foreign_key,
|
61
|
+
assignable_values: "#{ other_model.name(:class) }.all.to_a",
|
62
|
+
allow_blank: true,
|
63
|
+
associated_model: other_model
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def render
|
68
|
+
Generators::ModelGenerator.new(self).invoke_all
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
attr_accessor :_belongs_tos
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
File without changes
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# class for the Attribute element.
|
3
3
|
|
4
4
|
require 'katapult/element'
|
5
|
-
require 'katapult/action'
|
5
|
+
require 'katapult/elements/action'
|
6
6
|
require 'generators/katapult/web_ui/web_ui_generator'
|
7
7
|
|
8
8
|
module Katapult
|
@@ -14,7 +14,6 @@ module Katapult
|
|
14
14
|
RAILS_ACTIONS = %w[ index show new create edit update destroy ]
|
15
15
|
UnknownActionError = Class.new(StandardError)
|
16
16
|
UnknownModelError = Class.new(StandardError)
|
17
|
-
MissingLabelAttrError = Class.new(StandardError)
|
18
17
|
|
19
18
|
def initialize(*args)
|
20
19
|
self.actions = []
|
@@ -41,8 +40,7 @@ module Katapult
|
|
41
40
|
|
42
41
|
def model
|
43
42
|
model_name = @model || self.name
|
44
|
-
application_model.get_model
|
45
|
-
"Cannot find a model named #{model_name}"
|
43
|
+
application_model.get_model! model_name
|
46
44
|
end
|
47
45
|
|
48
46
|
def params
|
@@ -81,16 +79,8 @@ module Katapult
|
|
81
79
|
end
|
82
80
|
|
83
81
|
def render
|
84
|
-
validate!
|
85
82
|
Generators::WebUIGenerator.new(self).invoke_all
|
86
83
|
end
|
87
84
|
|
88
|
-
private
|
89
|
-
|
90
|
-
def validate!
|
91
|
-
model.label_attr.present? or raise MissingLabelAttrError,
|
92
|
-
'Cannot render a WebUI without a model with a label attribute'
|
93
|
-
end
|
94
|
-
|
95
85
|
end
|
96
86
|
end
|
data/lib/katapult/generator.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# The
|
1
|
+
# The base class for katapult element generators
|
2
2
|
|
3
3
|
require 'rails/generators'
|
4
|
-
require 'katapult/generator_goodies'
|
4
|
+
require 'katapult/support/generator_goodies'
|
5
5
|
|
6
6
|
module Katapult
|
7
7
|
class Generator < Rails::Generators::NamedBase
|
@@ -7,8 +7,15 @@ module Katapult::GeneratorGoodies
|
|
7
7
|
|
8
8
|
private
|
9
9
|
|
10
|
-
def app_name
|
11
|
-
File.basename(Dir.pwd)
|
10
|
+
def app_name(kind = nil)
|
11
|
+
machine_name = File.basename(Dir.pwd)
|
12
|
+
human_name = machine_name.tr('_', ' ').gsub(/\w+/, &:capitalize)
|
13
|
+
|
14
|
+
case kind.to_s
|
15
|
+
when '' then machine_name
|
16
|
+
when 'human' then human_name
|
17
|
+
else raise ArgumentError, "Unknown formatting: #{kind.inspect}"
|
18
|
+
end
|
12
19
|
end
|
13
20
|
|
14
21
|
# Override Thor method
|
data/lib/katapult/version.rb
CHANGED
data/script/console
CHANGED
@@ -4,11 +4,14 @@
|
|
4
4
|
# Run `script/console` from the gem root to start an IRB with the gem loaded.
|
5
5
|
|
6
6
|
# Remember to require classes before using them,
|
7
|
-
# i.e. `require 'katapult/model'` before `Katapult::Model
|
7
|
+
# i.e. `require 'katapult/elements/model'` before using `Katapult::Model`
|
8
|
+
|
9
|
+
require 'bundler/setup'
|
8
10
|
|
9
11
|
irb_options = [
|
10
12
|
'-Ilib', # add lib/ to load_path
|
11
|
-
'-d', # set $DEBUG = true
|
13
|
+
# '-d', # set $DEBUG = true
|
14
|
+
|
12
15
|
# Requires
|
13
16
|
'-rkatapult/version',
|
14
17
|
'-rrails',
|
data/script/update
CHANGED
data/spec/action_spec.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'katapult/application_model'
|
2
|
+
|
3
|
+
describe Katapult::ApplicationModel do
|
4
|
+
|
5
|
+
describe '#crud' do
|
6
|
+
it 'adds a model plus a web UI with CRUD actions' do
|
7
|
+
model = <<-MODEL
|
8
|
+
crud 'user' do |user|
|
9
|
+
user.attr :age
|
10
|
+
end
|
11
|
+
MODEL
|
12
|
+
|
13
|
+
subject = described_class.parse(model)
|
14
|
+
expect(subject.models.count).to be 1
|
15
|
+
user = subject.models.first
|
16
|
+
expect(user.name).to eq 'user'
|
17
|
+
expect(user.attrs.count).to be 1
|
18
|
+
expect(user.attrs.first.name).to eq 'age'
|
19
|
+
|
20
|
+
expect(subject.web_uis.count).to be 1
|
21
|
+
web_ui = subject.web_uis.first
|
22
|
+
expect(web_ui.actions.map(&:name)).to match Katapult::WebUI::RAILS_ACTIONS
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|