katapult 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/README.md +57 -9
  4. data/bin/katapult +7 -3
  5. data/features/application_model.feature +4 -1
  6. data/features/authenticate.feature +1 -18
  7. data/features/basics.feature +1 -0
  8. data/features/binary.feature +5 -7
  9. data/features/model.feature +42 -3
  10. data/features/step_definitions/rails_steps.rb +1 -1
  11. data/features/web_ui.feature +17 -5
  12. data/lib/generators/katapult/app_model/templates/lib/katapult/application_model.rb +3 -0
  13. data/lib/generators/katapult/basics/basics_generator.rb +3 -8
  14. data/lib/generators/katapult/basics/templates/README.md.tt +33 -0
  15. data/lib/generators/katapult/basics/templates/features/support/paths.rb +1 -1
  16. data/lib/generators/katapult/clearance/clearance_generator.rb +6 -2
  17. data/lib/generators/katapult/clearance/templates/config/initializers/clearance.rb +1 -0
  18. data/lib/generators/katapult/cucumber_features/cucumber_features_generator.rb +10 -0
  19. data/lib/generators/katapult/cucumber_features/templates/feature.feature +4 -3
  20. data/lib/generators/katapult/model/model_generator.rb +15 -0
  21. data/lib/generators/katapult/model/templates/model.rb +13 -3
  22. data/lib/generators/katapult/model_specs/model_specs_generator.rb +1 -1
  23. data/lib/generators/katapult/model_specs/templates/model_spec.rb +1 -1
  24. data/lib/generators/katapult/transform/transform_generator.rb +4 -7
  25. data/lib/generators/katapult/views/templates/_form.html.haml +16 -13
  26. data/lib/generators/katapult/views/templates/show.html.haml +2 -0
  27. data/lib/katapult/application_model.rb +68 -19
  28. data/lib/katapult/element.rb +13 -18
  29. data/lib/katapult/{action.rb → elements/action.rb} +0 -0
  30. data/lib/katapult/elements/association.rb +35 -0
  31. data/lib/katapult/{attribute.rb → elements/attribute.rb} +14 -5
  32. data/lib/katapult/{authentication.rb → elements/authentication.rb} +2 -5
  33. data/lib/katapult/elements/model.rb +76 -0
  34. data/lib/katapult/{navigation.rb → elements/navigation.rb} +0 -0
  35. data/lib/katapult/{web_ui.rb → elements/web_ui.rb} +2 -12
  36. data/lib/katapult/generator.rb +2 -2
  37. data/lib/katapult/{binary_util.rb → support/binary_util.rb} +2 -1
  38. data/lib/katapult/{generator_goodies.rb → support/generator_goodies.rb} +9 -2
  39. data/lib/katapult/version.rb +1 -1
  40. data/script/console +5 -2
  41. data/script/update +1 -1
  42. data/spec/action_spec.rb +1 -1
  43. data/spec/application_model_spec.rb +26 -0
  44. data/spec/association_spec.rb +12 -0
  45. data/spec/attribute_spec.rb +35 -1
  46. data/spec/model_spec.rb +5 -2
  47. data/spec/util_spec.rb +1 -1
  48. data/spec/web_ui_spec.rb +11 -33
  49. metadata +17 -13
  50. data/lib/katapult/model.rb +0 -45
  51. data/lib/katapult/parser.rb +0 -53
  52. data/spec/parser_spec.rb +0 -26
@@ -1,21 +1,31 @@
1
- class <%= class_name %> < ActiveRecord::Base
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
- assignable_values_for :<%= attr.name %>, <%= attr.options.slice(:allow_blank, :default) %> do
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
@@ -19,7 +19,7 @@ module Katapult
19
19
  no_tasks do
20
20
  def specable_attrs
21
21
  model.attrs.select do |attr|
22
- attr.assignable_values.present? or attr.default != nil
22
+ attr.assignable_values_as_list? or !attr.default.nil?
23
23
  end
24
24
  end
25
25
 
@@ -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
- # The application model transformation is split into two parts:
5
- # 1) parse the model into an object-based representation
6
- # 2) render the parsed model into code
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::Parser.new.parse(application_model, path)
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
- <%- if attribute.assignable_values -%>
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
- <%- else -%>
10
- <%- case attribute.type -%>
11
- <%- when :string -%>
12
+ <% else -%>
13
+ <%- case attribute.type -%>
14
+ <%- when :string -%>
12
15
  = form.text_field <%= attribute.name(:symbol) %>, class: 'form-control'
13
- <%- when :email -%>
16
+ <%- when :email -%>
14
17
  = form.email_field <%= attribute.name(:symbol) %>, class: 'form-control'
15
- <%- when :password -%>
18
+ <%- when :password -%>
16
19
  = form.password_field <%= attribute.name(:symbol) %>, class: 'form-control',
17
20
  autocomplete: 'new-password'
18
- <%- when :url -%>
21
+ <%- when :url -%>
19
22
  = form.url_field <%= attribute.name(:symbol) %>, class: 'form-control'
20
- <%- when :integer -%>
23
+ <%- when :integer -%>
21
24
  = form.number_field <%= attribute.name(:symbol) %>, class: 'form-control'
22
- <%- when :money -%>
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
- <%- when :text -%>
30
+ <%- when :text -%>
28
31
  = form.text_area <%= attribute.name(:symbol) %>, rows: 5, class: 'form-control'
29
- <%- when :flag -%>
32
+ <%- when :flag -%>
30
33
  .checkbox
31
34
  = form.label <%= attribute.name(:symbol) %> do
32
35
  = form.check_box <%= attribute.name(:symbol) %>
33
- <%- when :datetime -%>
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
@@ -35,5 +35,7 @@
35
35
  = <%= model_attribute %> ? 'Yes' : 'No'
36
36
  <%- when :datetime -%>
37
37
  = l(<%= model_attribute %>.to_date) if <%= model_attribute %>
38
+ <%- when :foreign_key -%>
39
+ = <%= model_attribute.sub /_id$/, '' %>
38
40
  <%- end -%>
39
41
  <%- end -%>
@@ -1,52 +1,101 @@
1
- # Internal representation of an application model file.
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
- attr_reader :models, :web_uis, :navigation, :authentication
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
- def add_model(model)
14
- model.set_application_model(self)
15
- @models << model
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
- def get_model(name)
19
- models.find { |m| m.name == name }
50
+ # DSL
51
+ def crud(name, &block)
52
+ model name, &block
53
+ web_ui name, &:crud
20
54
  end
21
55
 
22
- def add_web_ui(web_ui)
23
- web_ui.set_application_model(self)
24
- @web_uis << web_ui
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
- def set_navigation(navigation)
32
- navigation.set_application_model(self)
33
- @navigation = navigation
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
- def set_authentication(auth)
37
- auth.set_application_model(self)
38
- auth.ensure_user_model_attributes_present
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
@@ -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
- # Improve semantics in element classes
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(string email password url integer money text flag datetime json plain_json)
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 assignable_values
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
- MissingUserModel = Class.new(StandardError)
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) or raise MissingUserModel,
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
@@ -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(model_name) or raise UnknownModelError,
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
@@ -1,7 +1,7 @@
1
- # The katapult generator base class, slightly adapted from Rails generators.
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
@@ -2,7 +2,8 @@
2
2
 
3
3
  # This module is used inside the `katapult` binary and thus should not
4
4
  # require any gems in order to prevent version conflicts
5
- require_relative '../katapult/version'
5
+
6
+ require_relative '../../katapult/version'
6
7
  require 'bundler'
7
8
  require 'io/console'
8
9
 
@@ -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
@@ -1,7 +1,7 @@
1
1
  module Katapult
2
2
  ruby_version_path = File.expand_path('../../.ruby-version', __dir__)
3
3
 
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  RUBY_VERSION = File.read(ruby_version_path).strip
6
6
  RAILS_VERSION = '5.1.4'
7
7
  end
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.new :example_name`
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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require_relative '../lib/katapult/version'
4
- require_relative '../lib/katapult/binary_util'
4
+ require_relative '../lib/katapult/support/binary_util'
5
5
 
6
6
  u = Katapult::BinaryUtil
7
7
  version_path = 'lib/katapult/version.rb'
data/spec/action_spec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'katapult/action'
1
+ require 'katapult/elements/action'
2
2
 
3
3
  describe Katapult::Action do
4
4
 
@@ -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