katapult 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            require 'rails_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe <%= model.name :class %> do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              describe '#to_s' do
         | 
| 6 | 
            +
              <%- if model.label_attr -%>
         | 
| 7 | 
            +
                it 'returns the #<%= model.label_attr.name %> attribute' do
         | 
| 8 | 
            +
                  subject.<%= model.label_attr.name %> = <%= model.label_attr.test_value.inspect %>
         | 
| 9 | 
            +
                  expect(subject.to_s).to eql(<%= model.label_attr.test_value.to_s.inspect %>)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              <%- else -%>
         | 
| 12 | 
            +
                it 'returns its class name with its id' do
         | 
| 13 | 
            +
                  subject.id = 17
         | 
| 14 | 
            +
                  expect(subject.to_s).to eql("<%= model.name %>#17")
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              <%- end -%>
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            <% specable_attrs.each do |attr| -%>
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              describe '#<%= attr.name %>' do
         | 
| 21 | 
            +
              <%- if attr.assignable_values.present? -%>
         | 
| 22 | 
            +
                it { is_expected.to allow_value(<%= assignable_value_for(attr).inspect %>).for(:<%= attr.name %>) }
         | 
| 23 | 
            +
                it { is_expected.to_not allow_value(<%= unassignable_value_for(attr).inspect %>).for(:<%= attr.name %>) }
         | 
| 24 | 
            +
              <%- end -%>
         | 
| 25 | 
            +
              <%- unless attr.default.nil? -%>
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                it 'has a default' do
         | 
| 28 | 
            +
                  expect( subject.<%= attr.name %> ).to eql(<%= attr.default.inspect %>)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              <%- end -%>
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            <% end -%>
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # Generate navigation.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'katapult/generator'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Katapult
         | 
| 6 | 
            +
              module Generators
         | 
| 7 | 
            +
                class NavigationGenerator < Katapult::Generator
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  desc 'Generate the navigation'
         | 
| 10 | 
            +
                  source_root File.expand_path('../templates', __FILE__)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def create_navigation
         | 
| 14 | 
            +
                    template 'app/models/navigation.rb'
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  private
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def navigation
         | 
| 20 | 
            +
                    @element
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            class Navigation
         | 
| 2 | 
            +
              include Navy::Description
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              navigation :<%= name.downcase %> do
         | 
| 5 | 
            +
            <% navigation.wuis.each do |wui| -%>
         | 
| 6 | 
            +
              <%- if wui.find_action(:index) -%>
         | 
| 7 | 
            +
                section <%= navigation.section_name(wui) %>, <%= wui.model_name(:human_plural).titlecase.inspect %>, <%= wui.path(:index) %>
         | 
| 8 | 
            +
              <%- end -%>
         | 
| 9 | 
            +
            <% end -%>
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            # Generate files and directories from an application model file. Afterwards do
         | 
| 2 | 
            +
            # any setup left necessary (e.g. updating the database).
         | 
| 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 | 
            +
             | 
| 10 | 
            +
            module Katapult
         | 
| 11 | 
            +
              class TransformGenerator < Rails::Generators::Base
         | 
| 12 | 
            +
                desc 'Transform the katapult application model'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                argument :path, required: true, type: :string,
         | 
| 15 | 
            +
                  description: 'The path to the application model file'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
                def transform_application_model
         | 
| 19 | 
            +
                  say_status :parse, path
         | 
| 20 | 
            +
                  @app_model = Katapult::Parser.new.parse(path)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  say_status :render, "into #{application_name}"
         | 
| 23 | 
            +
                  @app_model.render
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def write_root_route
         | 
| 27 | 
            +
                  root_wui = @app_model.wuis.find do |wui|
         | 
| 28 | 
            +
                    wui.find_action :index
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  route "root '#{ root_wui.model_name(:variables) }#index'" if root_wui
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def migrate
         | 
| 35 | 
            +
                  run 'bin/rake db:drop:all &> /dev/null'
         | 
| 36 | 
            +
                  run 'bin/rake db:create db:migrate RAILS_ENV=development'
         | 
| 37 | 
            +
                  run 'bin/rake db:create db:migrate RAILS_ENV=test'
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                private
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def application_name
         | 
| 43 | 
            +
                   File.basename(Dir.pwd)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            % rails_actions = wui.actions - wui.custom_actions
         | 
| 2 | 
            +
            resources <%= model_name(:symbols) %>, only: <%= rails_actions.map(&:name).map(&:to_sym) %> do
         | 
| 3 | 
            +
                member do
         | 
| 4 | 
            +
            % wui.custom_actions.select(&:member?).each do |action|
         | 
| 5 | 
            +
                  <%= action.method %> '<%= action.name %>'
         | 
| 6 | 
            +
            % end
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
                collection do
         | 
| 9 | 
            +
            % wui.custom_actions.select(&:collection?).each do |action|
         | 
| 10 | 
            +
                  <%= action.method %> '<%= action.name %>'
         | 
| 11 | 
            +
            % end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            class <%= model_name(:classes) %>Controller < ApplicationController
         | 
| 2 | 
            +
            <%- if navigation -%>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              before_filter :set_section
         | 
| 5 | 
            +
            <%- end -%>
         | 
| 6 | 
            +
            <% if wui.find_action :index -%>
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def index
         | 
| 9 | 
            +
                <%= method_name(:load_collection) %>
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            <% end -%>
         | 
| 12 | 
            +
            <% if wui.find_action :show -%>
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def show
         | 
| 15 | 
            +
                <%= method_name(:load_object) %>
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            <% end -%>
         | 
| 18 | 
            +
            <% if wui.find_action :new -%>
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def new
         | 
| 21 | 
            +
                <%= method_name(:build) %>
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            <% end -%>
         | 
| 24 | 
            +
            <% if wui.find_action :create -%>
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              def create
         | 
| 27 | 
            +
                <%= method_name(:build) %>
         | 
| 28 | 
            +
                <%= method_name(:save) %> or render :new
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            <% end -%>
         | 
| 31 | 
            +
            <% if wui.find_action :edit -%>
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def edit
         | 
| 34 | 
            +
                <%= method_name(:load_object) %>
         | 
| 35 | 
            +
                <%= method_name(:build) %>
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            <% end -%>
         | 
| 38 | 
            +
            <% if wui.find_action :update -%>
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def update
         | 
| 41 | 
            +
                <%= method_name(:load_object) %>
         | 
| 42 | 
            +
                <%= method_name(:build) %>
         | 
| 43 | 
            +
                <%= method_name(:save) %> or render :edit
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            <% end -%>
         | 
| 46 | 
            +
            <% if wui.find_action :destroy -%>
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def destroy
         | 
| 49 | 
            +
                <%= method_name(:load_object) %>
         | 
| 50 | 
            +
                <%= model_name(:ivar) %>.destroy
         | 
| 51 | 
            +
                redirect_to <%= wui.path(:index) %>
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            <% end -%>
         | 
| 54 | 
            +
            <% wui.custom_actions.each do |action|  -%>
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              def <%= action.name %>
         | 
| 57 | 
            +
            <% if action.member? -%>
         | 
| 58 | 
            +
                <%= method_name(:load_object) %>
         | 
| 59 | 
            +
              <%- unless action.get? -%>
         | 
| 60 | 
            +
                redirect_to <%= model_name(:ivar) %>
         | 
| 61 | 
            +
              <%- end -%>
         | 
| 62 | 
            +
            <% elsif action.collection? -%>
         | 
| 63 | 
            +
                <%= method_name(:load_collection) %>
         | 
| 64 | 
            +
              <%- unless action.get? -%>
         | 
| 65 | 
            +
                redirect_to <%= wui.path(:index) %>
         | 
| 66 | 
            +
              <%- end -%>
         | 
| 67 | 
            +
            <% end -%>
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
            <% end -%>
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              private
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def <%= method_name(:load_collection) %>
         | 
| 74 | 
            +
                <%= model_name(:ivars) %> ||= <%= method_name(:scope) %>.to_a
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              def <%= method_name(:load_object) %>
         | 
| 78 | 
            +
                <%= model_name(:ivar) %> ||= <%= method_name(:scope) %>.find(params[:id])
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
              def <%= method_name(:build) %>
         | 
| 82 | 
            +
                <%= model_name(:ivar) %> ||= <%= method_name(:scope) %>.build
         | 
| 83 | 
            +
                <%= model_name(:ivar) %>.attributes = <%= method_name(:params) %>
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              def <%= method_name(:save) %>
         | 
| 87 | 
            +
                if <%= model_name(:ivar) %>.save
         | 
| 88 | 
            +
                  redirect_to <%= model_name(:ivar) %>
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              def <%= method_name(:params) %>
         | 
| 93 | 
            +
                <%= method_name(:params) %> = params[:<%= model_name(:variable) %>]
         | 
| 94 | 
            +
                <%= method_name(:params) %> ? <%= method_name(:params) %>.permit(<%= wui.model.attrs.map(&:name).map(&:to_sym) %>) : {}
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              def <%= method_name(:scope) %>
         | 
| 98 | 
            +
                <%= model_name(:class_name) %>.scoped
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            <%- if navigation -%>
         | 
| 102 | 
            +
              def set_section
         | 
| 103 | 
            +
                in_sections <%= navigation.section_name(wui) %>
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
            <%- end -%>
         | 
| 106 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            # Generate a controller, routes and view files for a WUI.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'katapult/generator'
         | 
| 4 | 
            +
            require 'generators/katapult/haml/haml_generator'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Katapult
         | 
| 7 | 
            +
              module Generators
         | 
| 8 | 
            +
                class WUIGenerator < Katapult::Generator
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  desc 'Generate a Web User Interface'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  check_class_collision suffix: 'Controller'
         | 
| 13 | 
            +
                  source_root File.expand_path('../templates', __FILE__)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def create_controller_file
         | 
| 17 | 
            +
                    template 'controller.rb', File.join('app', 'controllers', "#{ model_name(:variables) }_controller.rb")
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def add_route
         | 
| 21 | 
            +
                    route render_partial('_route.rb')
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def generate_views
         | 
| 25 | 
            +
                    Generators::HamlGenerator.new(wui).invoke_all
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  no_tasks do
         | 
| 29 | 
            +
                    def method_name(name)
         | 
| 30 | 
            +
                      case name
         | 
| 31 | 
            +
                      when :load_collection then "load_#{model_name :variables}"
         | 
| 32 | 
            +
                      when :load_object     then "load_#{model_name :variable}"
         | 
| 33 | 
            +
                      when :build           then "build_#{model_name :variable}"
         | 
| 34 | 
            +
                      when :save            then "save_#{model_name :variable}"
         | 
| 35 | 
            +
                      when :params          then "#{model_name :variable}_params"
         | 
| 36 | 
            +
                      when :scope           then "#{model_name :variable}_scope"
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def model_name(kind = nil)
         | 
| 41 | 
            +
                      wui.model_name(kind)
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    def navigation
         | 
| 45 | 
            +
                      wui.application_model.navigation
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  private
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def wui
         | 
| 52 | 
            +
                    @element
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
    
        data/lib/katapult.rb
    ADDED
    
    
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            # Models a controller action. To be used within the block of a WUI.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'katapult/element'
         | 
| 4 | 
            +
            require 'active_support/core_ext/module/delegation'
         | 
| 5 | 
            +
            require 'active_support/core_ext/string/inquiry'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Katapult
         | 
| 8 | 
            +
              class Action < Element
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                options :method, :scope
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def initialize(*args)
         | 
| 13 | 
            +
                  super
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  self.scope ||= (name == 'index') ? :collection : :member
         | 
| 16 | 
            +
                  set_method
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                delegate :post?, :get?, :put?, to: :method_inquiry
         | 
| 20 | 
            +
                delegate :member?, :collection?, to: :scope_inquiry
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def method_inquiry
         | 
| 25 | 
            +
                  @method.to_s.inquiry
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def scope_inquiry
         | 
| 29 | 
            +
                  @scope.to_s.inquiry
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def set_method
         | 
| 33 | 
            +
                  self.method ||= case name
         | 
| 34 | 
            +
                  when 'create', 'update'
         | 
| 35 | 
            +
                    :post
         | 
| 36 | 
            +
                  when 'destroy'
         | 
| 37 | 
            +
                    :delete
         | 
| 38 | 
            +
                  else # index, show, new, edit + custom actions
         | 
| 39 | 
            +
                    :get
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            # Internal representation of an application model file.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Katapult
         | 
| 4 | 
            +
              class ApplicationModel
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_reader :models, :wuis, :navigation
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize
         | 
| 9 | 
            +
                  @models = []
         | 
| 10 | 
            +
                  @wuis = []
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def add_model(model)
         | 
| 14 | 
            +
                  model.set_application_model(self)
         | 
| 15 | 
            +
                  @models << model
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def get_model(name)
         | 
| 19 | 
            +
                  models.find { |m| m.name == name }
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def add_wui(wui)
         | 
| 23 | 
            +
                  wui.set_application_model(self)
         | 
| 24 | 
            +
                  @wuis << wui
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def get_wui(name)
         | 
| 28 | 
            +
                  wuis.find { |w| w.name == name }
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def set_navigation(navigation)
         | 
| 32 | 
            +
                  navigation.set_application_model(self)
         | 
| 33 | 
            +
                  @navigation = navigation
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # ---
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def render
         | 
| 39 | 
            +
                  models.each &:render
         | 
| 40 | 
            +
                  wuis.each &:render
         | 
| 41 | 
            +
                  navigation.render if navigation
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            # Models a model attribute. To be used within the block of a model element.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'katapult/element'
         | 
| 4 | 
            +
            require 'active_support/core_ext/module/delegation'
         | 
| 5 | 
            +
            require 'active_support/core_ext/string/inquiry'
         | 
| 6 | 
            +
            require 'zlib'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Katapult
         | 
| 9 | 
            +
              class Attribute < Element
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                options :type, :default, :assignable_values, :allow_blank
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                UnknownTypeError = Class.new(StandardError)
         | 
| 14 | 
            +
                MissingOptionError = Class.new(StandardError)
         | 
| 15 | 
            +
                TYPES = %i(string email url integer money text markdown flag datetime)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize(*args)
         | 
| 18 | 
            +
                  super
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  self.type ||= :email if name.to_s =~ /email/
         | 
| 21 | 
            +
                  self.type ||= :string
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  validate
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                delegate :flag?, to: :type_inquiry
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def has_defaults?
         | 
| 29 | 
            +
                  default and not [flag?, assignable_values].any?
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def for_migration
         | 
| 33 | 
            +
                  db_type = case type
         | 
| 34 | 
            +
                  when :email, :url
         | 
| 35 | 
            +
                    'string'
         | 
| 36 | 
            +
                  when :flag
         | 
| 37 | 
            +
                    'boolean'
         | 
| 38 | 
            +
                  when :money
         | 
| 39 | 
            +
                    'decimal{10,2}' # {precision,scale} = total digits, decimal places
         | 
| 40 | 
            +
                  else
         | 
| 41 | 
            +
                    type
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  "#{name}:#{db_type}"
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def test_value
         | 
| 48 | 
            +
                  if assignable_values
         | 
| 49 | 
            +
                    assignable_values.first
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  else
         | 
| 52 | 
            +
                    case type
         | 
| 53 | 
            +
                    when :string     then "#{name}-string"
         | 
| 54 | 
            +
                    when :email      then "#{name}@example.com"
         | 
| 55 | 
            +
                    when :url        then "#{name}.example.com"
         | 
| 56 | 
            +
                    when :text       then "#{name}-text"
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    # Deterministically generate a value from the attribute's name
         | 
| 59 | 
            +
                    when :integer    then Zlib.crc32(name).modulo(1000)
         | 
| 60 | 
            +
                    when :money      then Zlib.crc32(name).modulo(1000) / 100.0
         | 
| 61 | 
            +
                    when :datetime   then Time.at(Zlib.crc32(name))
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                private
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def type_inquiry
         | 
| 69 | 
            +
                  @type.to_s.inquiry
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def validate
         | 
| 73 | 
            +
                  TYPES.include?(type) or raise UnknownTypeError,
         | 
| 74 | 
            +
                    "Attribute type :#{type} is not supported. Use one of #{TYPES.inspect}."
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  if flag? and default.nil?
         | 
| 77 | 
            +
                    raise MissingOptionError,
         | 
| 78 | 
            +
                      "The :flag attribute '#{name}' requires a default (true or false)."
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         |