reativo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []