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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +61 -0
- data/Rakefile +32 -0
- data/app/assets/config/reativo_manifest.js +2 -0
- data/app/assets/javascripts/reativo/application.js +15 -0
- data/app/assets/stylesheets/reativo/application.css +15 -0
- data/app/controllers/reativo/application_controller.rb +5 -0
- data/app/controllers/reativo/crud_controller.rb +182 -0
- data/app/helpers/reativo/application_helper.rb +4 -0
- data/app/jobs/reativo/application_job.rb +4 -0
- data/app/mailers/reativo/application_mailer.rb +6 -0
- data/app/models/reativo/application_record.rb +5 -0
- data/app/models/reativo/cell/component.rb +36 -0
- data/app/models/reativo/cell/theme.rb +34 -0
- data/app/models/reativo/cuid.rb +17 -0
- data/app/models/reativo/representer/errors.rb +8 -0
- data/app/models/reativo/view/component.erb +1 -0
- data/app/views/layouts/reativo/application.html.erb +16 -0
- data/config/routes.rb +2 -0
- data/lib/generators/reativo/USAGE +23 -0
- data/lib/generators/reativo/reativo_generator.rb +63 -0
- data/lib/generators/reativo/templates/contract/create.erb +7 -0
- data/lib/generators/reativo/templates/contract/update.erb +7 -0
- data/lib/generators/reativo/templates/operation/create.erb +16 -0
- data/lib/generators/reativo/templates/operation/destroy.erb +12 -0
- data/lib/generators/reativo/templates/operation/index.erb +33 -0
- data/lib/generators/reativo/templates/operation/show.erb +11 -0
- data/lib/generators/reativo/templates/operation/update.erb +16 -0
- data/lib/generators/reativo/templates/representer/create.erb +6 -0
- data/lib/generators/reativo/templates/representer/index.erb +10 -0
- data/lib/generators/reativo/templates/representer/module.erb +9 -0
- data/lib/generators/reativo/templates/representer/update.erb +6 -0
- data/lib/reativo.rb +7 -0
- data/lib/reativo/engine.rb +24 -0
- data/lib/reativo/migrations/general.rb +13 -0
- data/lib/reativo/migrations/table.rb +13 -0
- data/lib/reativo/version.rb +3 -0
- data/lib/tasks/reativo_tasks.rake +4 -0
- metadata +263 -0
checksums.yaml
ADDED
@@ -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
|
data/MIT-LICENSE
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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).
|
data/Rakefile
ADDED
@@ -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,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,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,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 @@
|
|
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>
|
data/config/routes.rb
ADDED
@@ -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,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
|
data/lib/reativo.rb
ADDED
@@ -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
|
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: []
|