reativo 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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +61 -0
  4. data/Rakefile +32 -0
  5. data/app/assets/config/reativo_manifest.js +2 -0
  6. data/app/assets/javascripts/reativo/application.js +15 -0
  7. data/app/assets/stylesheets/reativo/application.css +15 -0
  8. data/app/controllers/reativo/application_controller.rb +5 -0
  9. data/app/controllers/reativo/crud_controller.rb +182 -0
  10. data/app/helpers/reativo/application_helper.rb +4 -0
  11. data/app/jobs/reativo/application_job.rb +4 -0
  12. data/app/mailers/reativo/application_mailer.rb +6 -0
  13. data/app/models/reativo/application_record.rb +5 -0
  14. data/app/models/reativo/cell/component.rb +36 -0
  15. data/app/models/reativo/cell/theme.rb +34 -0
  16. data/app/models/reativo/cuid.rb +17 -0
  17. data/app/models/reativo/representer/errors.rb +8 -0
  18. data/app/models/reativo/view/component.erb +1 -0
  19. data/app/views/layouts/reativo/application.html.erb +16 -0
  20. data/config/routes.rb +2 -0
  21. data/lib/generators/reativo/USAGE +23 -0
  22. data/lib/generators/reativo/reativo_generator.rb +63 -0
  23. data/lib/generators/reativo/templates/contract/create.erb +7 -0
  24. data/lib/generators/reativo/templates/contract/update.erb +7 -0
  25. data/lib/generators/reativo/templates/operation/create.erb +16 -0
  26. data/lib/generators/reativo/templates/operation/destroy.erb +12 -0
  27. data/lib/generators/reativo/templates/operation/index.erb +33 -0
  28. data/lib/generators/reativo/templates/operation/show.erb +11 -0
  29. data/lib/generators/reativo/templates/operation/update.erb +16 -0
  30. data/lib/generators/reativo/templates/representer/create.erb +6 -0
  31. data/lib/generators/reativo/templates/representer/index.erb +10 -0
  32. data/lib/generators/reativo/templates/representer/module.erb +9 -0
  33. data/lib/generators/reativo/templates/representer/update.erb +6 -0
  34. data/lib/reativo.rb +7 -0
  35. data/lib/reativo/engine.rb +24 -0
  36. data/lib/reativo/migrations/general.rb +13 -0
  37. data/lib/reativo/migrations/table.rb +13 -0
  38. data/lib/reativo/version.rb +3 -0
  39. data/lib/tasks/reativo_tasks.rake +4 -0
  40. metadata +263 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ca2acc8095a64327496ebd9251d017cc8e73e19e9912f1eaab1975ff1f0a84c4
4
+ data.tar.gz: 6ad098644314730509fddcfdb191e9a175806ef5a281fb018c67a44742546b5e
5
+ SHA512:
6
+ metadata.gz: 9b25b1dce0313894dad8a3f54944e69a42ccb0124c545ef7a0888e54213c90ecddcd2deddcce421eb3fa44c826b6bdc68a8ee6a8c5bbbc1cc76daa5c1c29e56f
7
+ data.tar.gz: 9d0a98422bd8da257fa57d257050d7c058e2e63d2ac618cafc3b941cfc32bbd67438bb28a7fa69c5ceea60fbb94ec4fe8d0a4301dcda6753a49cceec13b3b2a4
@@ -0,0 +1,20 @@
1
+ Copyright 2019 Celso Fernandes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ # Reativo
2
+
3
+ It's my personal library, where I try to make Rails more Reactive (Reativo is the portuguese word for Reactive).
4
+
5
+ No, it's **NOT** a replaced for [react-rails](https://github.com/reactjs/react-rails/) or [webpacker](https://github.com/rails/webpacker) and will never be. Actually it heavily rely on both, built on shoulders of giants.
6
+
7
+ So what is it? I've been seen myself replicating code over some rails projects, with some _patterns_ I've been constantly using, so one day I decided, I'm over! I need a gem to make myself easier to use.
8
+
9
+ And here I am
10
+
11
+ This gem rely a lot on Trailblazer ecossystem, and make part of my workflow.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'reativo'
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ The basic usage is include the concern on your controller and set the layout component.
24
+
25
+ ```ruby
26
+ class TodosController < ApplicationController
27
+ include Reativo::CrudController
28
+
29
+ def theme_cell
30
+ Theme::Cell::Layout
31
+ end
32
+ end
33
+ ```
34
+
35
+ Not sure about how to customize? check the [Reativo::CrudController](https://github.com/fernandes/reativo/blob/master/app/controllers/reativo/crud_controller.rb) and check how it works, I tried to split so make easier to overwrite, like normal Ruby 😉
36
+
37
+ A common problem is, if you are using trailblazer < 2.1, you can overwrite `result_model` to use a string key
38
+
39
+ ```ruby
40
+ def result_model
41
+ result['model']
42
+ end
43
+ ```
44
+
45
+ ## Generator
46
+
47
+ It comes with a generator for Trailblazer, so, yeah!, you can generate the operations, contracts and representers!
48
+
49
+ ```bash
50
+ rails g reativo
51
+ ```
52
+
53
+ And check the [usage](https://github.com/fernandes/reativo/blob/master/lib/generators/reativo/USAGE)
54
+
55
+ ## Contributing
56
+
57
+ Please, help contributing, try to fix more than you break and world will be a better place! 😉
58
+
59
+ ## License
60
+
61
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Reativo'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/reativo .js
2
+ //= link_directory ../stylesheets/reativo .css
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require activestorage
15
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ module Reativo
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,182 @@
1
+ module Reativo
2
+ module CrudController
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ def theme_cell
7
+ raise Exception.new('Please specify your theme cell here')
8
+ end
9
+
10
+ def trb(cell_constant, model, options: {}, rails_options: {})
11
+ render(
12
+ {
13
+ html: cell(
14
+ cell_constant,
15
+ model,
16
+ {
17
+ layout: theme_cell,
18
+ context: _run_options({ flash: flash, controller: self }),
19
+ }.merge(options)
20
+ )
21
+ }.merge(rails_options)
22
+ )
23
+ end
24
+
25
+ def component(component, options: {}, rails_options: {}, **props)
26
+ component_options = options.merge!(
27
+ context: _run_options({
28
+ flash: flash, controller: self, component: component, props: props, result: result
29
+ })
30
+ )
31
+ trb(Reativo::Cell::Component, nil, options: component_options, rails_options: rails_options)
32
+ end
33
+
34
+ def index
35
+ run index_op
36
+
37
+ respond_to do |format|
38
+ format.html { component(index_compo, model: result_model) }
39
+ format.json {
40
+ json = Rails.cache.fetch("api/#{result[:cache_key]}", expires_in: 12.hours) do
41
+ result_model.extend(result['representer.render.class']).to_json
42
+ end
43
+ render json: json
44
+ }
45
+ end
46
+ end
47
+
48
+ def show
49
+ run show_op
50
+ respond_to do |format|
51
+ decorated_model = result_model ? result_model.extend(result['representer.render.class']) : nil
52
+ format.html { component(show_compo, model: (decorated_model ? decorated_model.to_hash : nil)) }
53
+ format.json {
54
+ json = Rails.cache.fetch("api/#{result[:cache_key]}", expires_in: 12.hours) do
55
+ decorated_model ? decorated_model.to_json : nil
56
+ end
57
+ render json: json
58
+ }
59
+ end
60
+ end
61
+
62
+ def new
63
+ respond_to do |format|
64
+ format.html { component(new_compo) }
65
+ end
66
+ end
67
+
68
+ def edit
69
+ run edit_op
70
+
71
+ decorated_model = result_model ? result_model.extend(result['representer.render.class']) : nil
72
+ component(edit_compo, model: decorated_model ? decorated_model.to_hash : nil)
73
+ end
74
+
75
+ def create
76
+ run create_op
77
+
78
+ respond_to do |format|
79
+ if result.success?
80
+ flash[:notice] = "#{model_name} was successfully created."
81
+ format.html { redirect_to result_model, notice: "#{model_name} was successfully created." }
82
+ format.json { render json: result_model.extend(result['representer.render.class']).to_json, status: :created }
83
+ else
84
+ format.html { component(new_compo) }
85
+ format.json { render json: result_model.errors, status: :unprocessable_entity }
86
+ end
87
+ end
88
+ end
89
+
90
+ def update
91
+ run update_op
92
+
93
+ respond_to do |format|
94
+ if result.success?
95
+ format.html { redirect_to result_model, notice: "#{model_name} was successfully updated." }
96
+ format.json { render json: result_model.extend(result['representer.render.class']).to_json }
97
+ else
98
+ format.html {
99
+ decorated_model = result_model ? result_model.extend(result['representer.render.class']) : nil
100
+ component(edit_compo, model: decorated_model ? decorated_model.to_hash : nil)
101
+ }
102
+ format.json { render json: result["representer.errors.class"].new(result["result.contract.default"].errors.messages).to_json, status: :unprocessable_entity }
103
+ end
104
+ end
105
+ end
106
+
107
+ def destroy
108
+ run destroy_op
109
+
110
+ respond_to do |format|
111
+ format.html { redirect_to send("#{collection_name.underscore}_url".to_sym), notice: "#{model_name} was successfully destroyed." }
112
+ format.json { head :no_content }
113
+ end
114
+ end
115
+
116
+ private
117
+ def result
118
+ @_result
119
+ end
120
+
121
+ def result_model
122
+ result[:model]
123
+ end
124
+
125
+ def index_op
126
+ action_op('index')
127
+ end
128
+
129
+ def index_compo
130
+ action_compo('index')
131
+ end
132
+
133
+ def show_op
134
+ action_op('show')
135
+ end
136
+
137
+ def show_compo
138
+ action_compo('show')
139
+ end
140
+
141
+ def create_op
142
+ action_op('create')
143
+ end
144
+
145
+ def new_compo
146
+ action_compo('new')
147
+ end
148
+
149
+ def edit_op
150
+ action_op("edit")
151
+ end
152
+
153
+ def edit_compo
154
+ action_compo('edit')
155
+ end
156
+
157
+ def update_op
158
+ action_op('update')
159
+ end
160
+
161
+ def destroy_op
162
+ action_op('destroy')
163
+ end
164
+
165
+ def action_op(action)
166
+ "#{collection_name}::Operation::#{action.camelize}".constantize
167
+ end
168
+
169
+ def action_compo(action)
170
+ "#{collection_name.underscore}/#{action.camelize}"
171
+ end
172
+
173
+ def model_name
174
+ collection_name.singularize
175
+ end
176
+
177
+ def collection_name
178
+ self.class.to_s.gsub!(/Controller$/, '')
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,4 @@
1
+ module Reativo
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Reativo
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Reativo
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Reativo
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ module Reativo::Cell
2
+ class Component < Trailblazer::Cell
3
+ include React::Rails::ViewHelper
4
+ include Cell::Caching::Notifications
5
+
6
+ self.prefixes << File.join(File.dirname(File.expand_path(__FILE__)), '..', 'view')
7
+
8
+ cache :show, if: :cache? do
9
+ self.context[:result][:cache_key]
10
+ end
11
+
12
+ def datamodel
13
+ operation[:model]
14
+ end
15
+
16
+ def component
17
+ self.context[:component]
18
+ end
19
+
20
+ def props
21
+ result = self.context[:result] || {}
22
+ additional_props = result[:view] || {}
23
+ self.context[:props].merge!(additional_props)
24
+ end
25
+
26
+ def operation
27
+ model
28
+ end
29
+
30
+ def cache?(*args)
31
+ return false if self.context[:result].nil?
32
+ return true if self.context[:result][:cache_key]
33
+ false
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ module Reativo::Cell
2
+ class Theme < Trailblazer::Cell
3
+ include ActionView::Helpers::CsrfHelper
4
+ include ActionView::Helpers::CspHelper
5
+ include Webpacker::Helper
6
+ include React::Rails::ViewHelper
7
+
8
+ def protect_against_forgery?
9
+ context[:controller].send(:protect_against_forgery?)
10
+ end
11
+
12
+ def content_security_policy?
13
+ context[:controller].send(:content_security_policy?)
14
+ end
15
+
16
+ def form_authenticity_token
17
+ context[:controller].send(:form_authenticity_token)
18
+ end
19
+
20
+ def flash_messages(opts = {})
21
+ flash_messages = []
22
+ controller.flash.each do |type, message|
23
+ type = 'success' if type == 'notice'
24
+ type = 'error' if type == 'alert'
25
+ flash_messages << {title: message, type: type} if message
26
+ end
27
+ flash_messages
28
+ end
29
+
30
+ def current_user
31
+ context[:controller].current_user
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ module Reativo
2
+ module Cuid
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_save :set_cuid, on: :create
7
+
8
+ def self.find_cuid(id)
9
+ self.find_by(cuid: id)
10
+ end
11
+
12
+ def set_cuid
13
+ self.cuid = ::Cuid::generate if self.cuid.nil?
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ require 'representable/json/hash'
2
+
3
+ module Reativo::Representer
4
+ class Errors < Representable::Decorator
5
+ include Representable::JSON::Hash
6
+ self.representation_wrap = :errors
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ <%= react_component(component, **props) %>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Reativo</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "reativo/application", media: "all" %>
9
+ <%= javascript_include_tag "reativo/application" %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
@@ -0,0 +1,2 @@
1
+ Reativo::Engine.routes.draw do
2
+ end
@@ -0,0 +1,23 @@
1
+ Description:
2
+ Trailblazer generator for my trailblazer workflow
3
+
4
+ Example:
5
+ rails g reativo Admin::Todos Todo --properties title completed --crud --view_model
6
+
7
+ This will create:
8
+ app/concepts/admin/todos/{operation, representer}/index.rb
9
+ app/concepts/admin/todos/{contract, operation, representer}/create.rb
10
+ app/concepts/admin/todos/{operation}/show.rb
11
+ app/concepts/admin/todos/{contract, operation, representer}/update.rb
12
+ app/concepts/admin/todos/{operation}/destroy.rb
13
+ app/concepts/admin/todos/representer/todo_module.rb # the model representation
14
+
15
+ Example 2:
16
+ If you don't wanna create for all actions, you can specify
17
+
18
+ rails g reativo Admin::Todos Todo --properties title completed --actions index create --view_model
19
+
20
+ This will create:
21
+ app/concepts/admin/todos/{operation, representer}/index.rb
22
+ app/concepts/admin/todos/{contract, operation, representer}/create.rb
23
+ app/concepts/admin/todos/representer/todo_module.rb
@@ -0,0 +1,63 @@
1
+ class ReativoGenerator < Rails::Generators::NamedBase
2
+ MAP = {
3
+ index: { operation: true, contract: false, representer: true},
4
+ create: { operation: true, contract: true, representer: true},
5
+ show: { operation: true, contract: false, representer: false},
6
+ update: { operation: true, contract: true, representer: true},
7
+ destroy: { operation: true, contract: false, representer: false},
8
+ }
9
+
10
+ source_root File.expand_path('templates', __dir__)
11
+ argument :model_name, required: true
12
+ class_option :view_model, type: :boolean, default: false, aliases: ['-v']
13
+ class_option :crud, type: :boolean, default: false, aliases: ['-c']
14
+ class_option :actions, type: :array, default: []
15
+ class_option :properties, type: :array, default: [], aliases: ['--props']
16
+
17
+ def generate_operations
18
+ representer_module = false
19
+ actions = options['actions'] || []
20
+
21
+ actions = ['index', 'create', 'show', 'update', 'destroy'] if options[:crud]
22
+
23
+ actions.each do |action|
24
+ template "operation/#{action}.erb", concept_path("operation", action) if has_operation?(action)
25
+ template "contract/#{action}.erb", concept_path("contract", action) if has_contract?(action)
26
+ if has_representer?(action)
27
+ template "representer/#{action}.erb", concept_path("representer", action)
28
+ representer_module = true
29
+ end
30
+ end
31
+
32
+ if representer_module
33
+ template "representer/module.erb", concept_path("representer", "#{model_name.underscore}_module")
34
+ end
35
+ end
36
+
37
+ private
38
+ def property_attribute(property)
39
+ return "property :#{property}"
40
+ end
41
+
42
+ def properties_symbols(include_id:)
43
+ args = options[:properties].dup
44
+ args.prepend(:id) if include_id
45
+ args.map { |x| ":#{x}" }.join(", ")
46
+ end
47
+
48
+ def concept_path(operation, action)
49
+ "app/concepts/#{class_name.underscore}/#{operation}/#{action}.rb"
50
+ end
51
+
52
+ def has_operation?(action)
53
+ MAP.dig(action.to_sym, :operation) || false
54
+ end
55
+
56
+ def has_contract?(action)
57
+ MAP.dig(action.to_sym, :contract) || false
58
+ end
59
+
60
+ def has_representer?(action)
61
+ MAP.dig(action.to_sym, :representer) || false
62
+ end
63
+ end
@@ -0,0 +1,7 @@
1
+ module <%= class_name %>::Contract
2
+ class Create < Reform::Form
3
+ include <%= class_name %>::Representer::<%= model_name %>Module
4
+
5
+ # validates :name, presence: true, length: {minimum: 1}
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module <%= class_name %>::Contract
2
+ class Update < Reform::Form
3
+ include <%= class_name %>::Representer::<%= model_name %>Module
4
+
5
+ # validates :name, presence: true, length: {minimum: 1}
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module <%= class_name %>::Operation
2
+ class Create < Trailblazer::Operation
3
+ class Present < Trailblazer::Operation
4
+ step Model(<%= model_name %>, :new)
5
+ step Contract::Build( constant: <%= class_name %>::Contract::Create )
6
+ end
7
+
8
+ step ->(options, params) { options["representer.render.class"] = <%= class_name %>::Representer::Create }
9
+ step ->(options, params) { options["representer.errors.class"] = Reativo::Representer::Errors }
10
+ step Nested( Present )
11
+
12
+ step Contract::Build(constant: <%= class_name %>::Contract::Create)
13
+ step Contract::Validate(key: '<%= model_name.underscore %>')
14
+ step Contract::Persist()
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module <%= class_name %>::Operation
2
+ class Create < Trailblazer::Operation
3
+ step ->(options, params) { options["representer.render.class"] = <%= class_name %>::Representer::Create }
4
+ step ->(options, params) { options["representer.errors.class"] = Reativo::Representer::Errors }
5
+ step Model( <%= model_name %>, :find )
6
+ step :destroy!
7
+
8
+ def destroy!(ctx, params:, current_user:, **)
9
+ options[:model].destroy
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ module <%= class_name %>::Operation
2
+ class Index < Trailblazer::Operation
3
+ <%- if options[:view_model] -%>
4
+ ViewModel = Struct.new(<%= properties_symbols(include_id: true) %>) do
5
+ # def cuid
6
+ # id
7
+ # end
8
+ end
9
+
10
+ <%- end -%>
11
+ step ->(options, params) { options["representer.render.class"] = <%= class_name %>::Representer::Index }
12
+ step ->(options, params) { options["representer.errors.class"] = Reativo::Representer::Errors }
13
+ step :scope!
14
+ step :model!
15
+ step :cache_key!
16
+
17
+ def scope!(ctx, params:, current_user:, **)
18
+ ctx[:scope] = <%= class_name.singularize %>.where(user: current_user).order(id: :asc)
19
+ end
20
+
21
+ def model!(ctx, params:, current_user:, **)
22
+ <%- if options[:view_model] -%>
23
+ ctx[:model] = ctx[:scope].pluck(<%= properties_symbols(include_id: true) %>).map { |x| ViewModel.new(*x) }
24
+ <%- else -%>
25
+ ctx[:model] = ctx[:scope]
26
+ <%- end -%>
27
+ end
28
+
29
+ def cache_key!(ctx, params:, current_user:, **)
30
+ ctx[:cache_key] = ctx[:scope].cache_key
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ module <%= class_name %>::Operation
2
+ class Show < Trailblazer::Operation
3
+ step ->(options, params) { options["representer.render.class"] = <%= class_name %>::Representer::Create }
4
+ step Model( <%= model_name %>, :find )
5
+ step :cache_key!
6
+
7
+ def cache_key!(opts, params:, current_user:, **)
8
+ opts[:cache_key] = opts[:model].cache_key_with_version
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module <%= class_name %>::Operation
2
+ class Update < Trailblazer::Operation
3
+ class Present < Trailblazer::Operation
4
+ step Model(<%= model_name %>, :find)
5
+ step Contract::Build( constant: <%= class_name %>::Contract::Update )
6
+ end
7
+
8
+ step ->(options, params) { options["representer.render.class"] = <%= class_name %>::Representer::Update }
9
+ step ->(options, params) { options["representer.errors.class"] = Reativo::Representer::Errors }
10
+ step Nested( Present )
11
+
12
+ step Contract::Build(constant: <%= class_name %>::Contract::Update)
13
+ step Contract::Validate(key: '<%= model_name.underscore %>')
14
+ step Contract::Persist()
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ module <%= class_name %>::Representer
2
+ module Create
3
+ include Representable::JSON
4
+ include <%= model_name %>Module
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ module <%= class_name %>::Representer
2
+ module Index
3
+ include Representable::JSON::Collection
4
+
5
+ items class: <%= model_name %> do
6
+ include Representable::JSON
7
+ include <%= model_name %>Module
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module <%= class_name %>::Representer
2
+ module <%= model_name %>Module
3
+ include Reform::Form::Module
4
+
5
+ <%- options[:properties].each do |property| -%>
6
+ <%= property_attribute(property) %>
7
+ <%- end -%>
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module <%= class_name %>::Representer
2
+ module Update
3
+ include Representable::JSON
4
+ include <%= model_name %>Module
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Reativo
2
+ # Your code goes here...
3
+ end
4
+
5
+ require "reativo/migrations/table"
6
+ require "reativo/migrations/general"
7
+ require "reativo/engine"
@@ -0,0 +1,24 @@
1
+ require 'cells-erb'
2
+ require 'cells-rails'
3
+ require 'react-rails'
4
+ require 'reform'
5
+ require 'reform/rails'
6
+ require 'trailblazer'
7
+ require 'trailblazer/cells'
8
+ require 'trailblazer-rails'
9
+ require 'turbolinks'
10
+ require 'webpacker'
11
+ require 'multi_json'
12
+
13
+ module Reativo
14
+ class Engine < ::Rails::Engine
15
+ isolate_namespace Reativo
16
+
17
+ initializer "reativo.migrations.cuid" do |app|
18
+ require 'active_record'
19
+ require 'active_record/migration'
20
+ ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Reativo::Migrations::Table)
21
+ ActiveRecord::Migration.send(:include, Reativo::Migrations::General)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ module Reativo::Migrations
2
+ module General
3
+ def self.included(base) # :nodoc:
4
+ base.send(:include, InstanceMethods)
5
+ end
6
+
7
+ module InstanceMethods
8
+ def cuid_index table, **options
9
+ add_index table, :cuid, unique: true, **options
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Reativo::Migrations
2
+ module Table
3
+ def self.included(base) # :nodoc:
4
+ base.send(:include, InstanceMethods)
5
+ end
6
+
7
+ module InstanceMethods
8
+ def cuid column_name = :cuid
9
+ column(column_name, :string, limit: 25, null: false)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Reativo
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :reativo do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,263 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reativo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Celso Fernandes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: cells-erb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cells-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: multi_json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: react-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: reform-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.2.0.rc1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.2.0.rc1
97
+ - !ruby/object:Gem::Dependency
98
+ name: reform
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2'
111
+ - !ruby/object:Gem::Dependency
112
+ name: trailblazer-cells
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: trailblazer-rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2'
139
+ - !ruby/object:Gem::Dependency
140
+ name: trailblazer
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: turbolinks
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '5'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '5'
167
+ - !ruby/object:Gem::Dependency
168
+ name: webpacker
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '4'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '4'
181
+ - !ruby/object:Gem::Dependency
182
+ name: pg
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ description: Make Rails more reactive
196
+ email:
197
+ - celso.fernandes@gmail.com
198
+ executables: []
199
+ extensions: []
200
+ extra_rdoc_files: []
201
+ files:
202
+ - MIT-LICENSE
203
+ - README.md
204
+ - Rakefile
205
+ - app/assets/config/reativo_manifest.js
206
+ - app/assets/javascripts/reativo/application.js
207
+ - app/assets/stylesheets/reativo/application.css
208
+ - app/controllers/reativo/application_controller.rb
209
+ - app/controllers/reativo/crud_controller.rb
210
+ - app/helpers/reativo/application_helper.rb
211
+ - app/jobs/reativo/application_job.rb
212
+ - app/mailers/reativo/application_mailer.rb
213
+ - app/models/reativo/application_record.rb
214
+ - app/models/reativo/cell/component.rb
215
+ - app/models/reativo/cell/theme.rb
216
+ - app/models/reativo/cuid.rb
217
+ - app/models/reativo/representer/errors.rb
218
+ - app/models/reativo/view/component.erb
219
+ - app/views/layouts/reativo/application.html.erb
220
+ - config/routes.rb
221
+ - lib/generators/reativo/USAGE
222
+ - lib/generators/reativo/reativo_generator.rb
223
+ - lib/generators/reativo/templates/contract/create.erb
224
+ - lib/generators/reativo/templates/contract/update.erb
225
+ - lib/generators/reativo/templates/operation/create.erb
226
+ - lib/generators/reativo/templates/operation/destroy.erb
227
+ - lib/generators/reativo/templates/operation/index.erb
228
+ - lib/generators/reativo/templates/operation/show.erb
229
+ - lib/generators/reativo/templates/operation/update.erb
230
+ - lib/generators/reativo/templates/representer/create.erb
231
+ - lib/generators/reativo/templates/representer/index.erb
232
+ - lib/generators/reativo/templates/representer/module.erb
233
+ - lib/generators/reativo/templates/representer/update.erb
234
+ - lib/reativo.rb
235
+ - lib/reativo/engine.rb
236
+ - lib/reativo/migrations/general.rb
237
+ - lib/reativo/migrations/table.rb
238
+ - lib/reativo/version.rb
239
+ - lib/tasks/reativo_tasks.rake
240
+ homepage: https://github.com/fernandes/reativo
241
+ licenses:
242
+ - MIT
243
+ metadata: {}
244
+ post_install_message:
245
+ rdoc_options: []
246
+ require_paths:
247
+ - lib
248
+ required_ruby_version: !ruby/object:Gem::Requirement
249
+ requirements:
250
+ - - ">="
251
+ - !ruby/object:Gem::Version
252
+ version: '0'
253
+ required_rubygems_version: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
258
+ requirements: []
259
+ rubygems_version: 3.0.1
260
+ signing_key:
261
+ specification_version: 4
262
+ summary: Make Rails more reactive
263
+ test_files: []