yuba 0.0.1.pre → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +215 -8
- data/lib/generators/yuba/form/form_generator.rb +9 -0
- data/lib/generators/yuba/form/templates/form.tt +4 -0
- data/lib/generators/yuba/service/service_generator.rb +9 -0
- data/lib/generators/yuba/service/templates/service.tt +6 -0
- data/lib/generators/yuba/view_model/templates/view_model.tt +4 -0
- data/lib/generators/yuba/view_model/view_model_generator.rb +9 -0
- data/lib/yuba.rb +8 -0
- data/lib/yuba/form.rb +9 -54
- data/lib/yuba/form/coercion.rb +36 -0
- data/lib/yuba/form/multi_parameter_attributes.rb +52 -0
- data/lib/yuba/rendering.rb +33 -0
- data/lib/yuba/service.rb +40 -17
- data/lib/yuba/version.rb +1 -1
- data/lib/yuba/view_model.rb +31 -12
- metadata +116 -11
- data/lib/yuba/form/attribute.rb +0 -9
- data/lib/yuba/form/attributes.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0f50e10de1c64847c7dfb2087e0b8ca416ed1d5
|
4
|
+
data.tar.gz: f1d38de018095e4b0651a0c80c842cadb2070e20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e2b3a1cb8b9f0ac254f67d504ddf99ffc47b02d322e7eded4a1475597eb8f6374c08c59e19ec39662dd2446c299973237ec8f46fa8cc6bd62e1d22bdfe57406
|
7
|
+
data.tar.gz: 8673f827dd5ecf5a140bfe8774b92de85bdf20bb9f2ff1feb894dc55f1fb8f7ffd01ea4105e9060d72f26b286650678d74da30739c9b6f36e118ce171b36c0fa
|
data/README.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# Yuba
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status](https://travis-ci.org/willnet/yuba.svg?branch=master)](https://travis-ci.org/willnet/yuba)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/yuba.svg)](https://badge.fury.io/rb/yuba)
|
5
|
+
|
6
|
+
## warning
|
7
|
+
|
8
|
+
Version of this gem is now 0.0.x. It works but there must be occasional breaking changes to the API.
|
9
|
+
|
10
|
+
## Summary
|
4
11
|
|
5
12
|
Yuba add new layers to rails.
|
6
13
|
|
@@ -8,11 +15,12 @@ Yuba add new layers to rails.
|
|
8
15
|
- Form
|
9
16
|
- ViewModel
|
10
17
|
|
11
|
-
|
18
|
+
It is convenient to use them in combination, but you can use them even by themselves.
|
12
19
|
|
13
|
-
|
20
|
+
If you have difficulties with large rails application, Yuba help you.
|
14
21
|
|
15
22
|
## Installation
|
23
|
+
|
16
24
|
Add this line to your application's Gemfile:
|
17
25
|
|
18
26
|
```ruby
|
@@ -20,17 +28,216 @@ gem 'yuba'
|
|
20
28
|
```
|
21
29
|
|
22
30
|
And then execute:
|
31
|
+
|
23
32
|
```bash
|
24
|
-
$ bundle
|
33
|
+
$ bundle install
|
25
34
|
```
|
26
35
|
|
27
|
-
|
28
|
-
|
29
|
-
|
36
|
+
## Support
|
37
|
+
|
38
|
+
- Rails 4.2+
|
39
|
+
- Ruby 2.2+
|
40
|
+
|
41
|
+
## ViewModel
|
42
|
+
|
43
|
+
ViewModel is useful when there are many instance variables in controller.
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
class PostViewModel < Yuba::ViewModel
|
47
|
+
property :post
|
48
|
+
property :author, public: true
|
49
|
+
property :other, optional: true
|
50
|
+
|
51
|
+
def title
|
52
|
+
post.title
|
53
|
+
end
|
54
|
+
|
55
|
+
def body
|
56
|
+
post.body
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Post = Struct.new(:title, :body)
|
61
|
+
post = Post.new('hello', 'world')
|
62
|
+
|
63
|
+
view_model = PostViewModel.new(post: post, author: 'willnet')
|
64
|
+
view.title #=> 'hello'
|
65
|
+
view.body #=> 'world'
|
66
|
+
view.author #=> 'willnet'
|
67
|
+
view.post #=> NoMethodError
|
68
|
+
```
|
69
|
+
|
70
|
+
### property
|
71
|
+
|
72
|
+
`.property` method register property to the class.
|
73
|
+
|
74
|
+
Those registered by property need to be passed as arguments to the `initialize` except when `optional: true` is attached. You get ArgumentError if you don't pass `property` to `initialize`.
|
75
|
+
|
76
|
+
Property is default to private. This means you can use it in internal the instance. If you want to use it as public, use `public: true` option.
|
77
|
+
|
78
|
+
### Auto Assign
|
79
|
+
|
80
|
+
You can use ViewModel in a controller like following
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class PostsController
|
84
|
+
def show
|
85
|
+
@view_model = PostViewModel.new(post: post, author: 'willnet')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
In view template, if you want to access post and author, you have to use `@view_model` instance variable like `@view_model.post.title`. if it feels troublesome, you can write like following
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
class PostsController
|
94
|
+
def show
|
95
|
+
view_model = PostViewModel.new(post: post, author: 'willnet')
|
96
|
+
render view_model: view_model
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
view_model option of render takes ViewModel, which get it's public methods (include public property) and assign them to instance variables in view template. So you can write `<%= @post.title %>` instead of `<%= @view_model.post.title %>`
|
102
|
+
|
103
|
+
## Service
|
104
|
+
|
105
|
+
Service is useful when controller has many application logic.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
class PostController < ApplicationController
|
109
|
+
def new
|
110
|
+
@post = CreatePostService.call(user: current_user).post
|
111
|
+
end
|
112
|
+
|
113
|
+
def create
|
114
|
+
service = CreatePostService.call(user: current_user, params: params)
|
115
|
+
|
116
|
+
if service.success?
|
117
|
+
redirect_to root_path
|
118
|
+
else
|
119
|
+
@post = service.post
|
120
|
+
render :new
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class CreatePostService < Yuba::Service
|
126
|
+
property :user, public: true
|
127
|
+
property :params, optional: true
|
128
|
+
|
129
|
+
def call
|
130
|
+
if post.save
|
131
|
+
notify_to_admin
|
132
|
+
else
|
133
|
+
fail!
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def post
|
138
|
+
user.posts.build(post_params)
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def notify_to_admin
|
144
|
+
AdminMailer.notify_create_post(post).deliver_later
|
145
|
+
end
|
146
|
+
|
147
|
+
def post_params
|
148
|
+
params.require(:post).permit(:title, :body)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
- `.property` method register property to the class like ViewModel.
|
154
|
+
- `.call` invokes `#call` after assigning arguments as properties.
|
155
|
+
- `#success?` returns `true` if you don't invoke `#fail!`
|
156
|
+
|
157
|
+
## Form
|
158
|
+
|
159
|
+
Form is just wrapper of [reform-rails](https://github.com/trailblazer/reform-rails) for now.
|
160
|
+
|
161
|
+
You can see documentation [here](http://trailblazer.to/gems/reform/rails.html).
|
162
|
+
|
163
|
+
## Combination Sample
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
class ArtistsController < ApplicationController
|
167
|
+
def new
|
168
|
+
@view_model = Artist::CreateService.new(params: params).view_model
|
169
|
+
end
|
170
|
+
|
171
|
+
def create
|
172
|
+
service = Artist::CreateService.call(params: params)
|
173
|
+
|
174
|
+
if service.success?
|
175
|
+
redirect_to artists_path
|
176
|
+
else
|
177
|
+
@view_model = service.view_model
|
178
|
+
render :new
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class Artist::CreateService < Yuba::Service
|
185
|
+
property :params
|
186
|
+
|
187
|
+
def call
|
188
|
+
if form.validate(params)
|
189
|
+
form.save
|
190
|
+
else
|
191
|
+
fail!
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def view_model
|
196
|
+
Artist::CreateViewModel.new(form: form)
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def form
|
202
|
+
@form ||= ArtistForm.new(Artist.new)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
class ArtistForm < Yuba::Form
|
209
|
+
property :name
|
210
|
+
|
211
|
+
validates :name, presence: true, length: { maximum: 100 }
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
class Artist::CreateViewModel < Yuba::ViewModel
|
217
|
+
property :form, public: true
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
## generators
|
222
|
+
|
223
|
+
You can use generators.
|
224
|
+
|
225
|
+
```
|
226
|
+
rails generate yuba:service create_artist
|
227
|
+
rails generate yuba:form artist
|
228
|
+
rails generate yuba:view_model artist_index
|
30
229
|
```
|
31
230
|
|
32
231
|
## Contributing
|
33
|
-
|
232
|
+
|
233
|
+
You can try to test by doing as following
|
234
|
+
|
235
|
+
```
|
236
|
+
git clone https://github.com/willnet/yuba.git
|
237
|
+
cd yuba
|
238
|
+
bundle
|
239
|
+
bundle exec rake
|
240
|
+
```
|
34
241
|
|
35
242
|
## License
|
36
243
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Yuba
|
2
|
+
class ViewModelGenerator < ::Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
def generate_view_model
|
6
|
+
template 'view_model.tt', File.join('app/view_models', class_path, "#{file_name}_view_model.rb")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
data/lib/yuba.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
+
require 'reform/rails'
|
2
|
+
require 'dry/types'
|
3
|
+
|
1
4
|
module Yuba
|
2
5
|
autoload :Form, 'yuba/form'
|
3
6
|
autoload :Service, 'yuba/service'
|
4
7
|
autoload :ViewModel, 'yuba/view_model'
|
8
|
+
autoload :Rendering, 'yuba/rendering'
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
ActionController::Base.include(Yuba::Rendering)
|
5
13
|
end
|
data/lib/yuba/form.rb
CHANGED
@@ -1,60 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
autoload :Attribute, 'yuba/form/attribute'
|
4
|
-
autoload :Attributes, 'yuba/form/attributes'
|
5
|
-
autoload :Collection, 'yuba/form/collection'
|
6
|
-
|
7
|
-
include ActiveModel::Model
|
8
|
-
class_attribute :_model_attribute
|
9
|
-
class_attribute :attributes
|
1
|
+
require 'yuba/form/coercion'
|
2
|
+
require 'yuba/form/multi_parameter_attributes'
|
10
3
|
|
4
|
+
module Yuba
|
5
|
+
class Form < ::Reform::Form
|
11
6
|
class << self
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
define_method("#{name}=") do |value|
|
19
|
-
write_attribute(name.to_s, value, block)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
include mod
|
23
|
-
end
|
24
|
-
|
25
|
-
def collection(name)
|
7
|
+
def inherited(subclass)
|
8
|
+
subclass.feature Coercion
|
9
|
+
subclass.feature MultiParameterAttributes
|
10
|
+
subclass.include Reform::Form::ActiveRecord
|
11
|
+
subclass.include Reform::Form::ActiveModel::ModelReflections
|
26
12
|
end
|
27
|
-
|
28
|
-
def model(name)
|
29
|
-
self._model_attribute = name
|
30
|
-
end
|
31
|
-
|
32
|
-
def build(**args)
|
33
|
-
new(**args)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def save
|
38
|
-
valid? && persist
|
39
|
-
end
|
40
|
-
|
41
|
-
def persist
|
42
|
-
end
|
43
|
-
|
44
|
-
def model
|
45
|
-
send(_model_attribute)
|
46
|
-
end
|
47
|
-
|
48
|
-
def model_name
|
49
|
-
model&.model_name
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def write_attribute(name, value, block)
|
55
|
-
# TODO: convert value by type of attribute
|
56
|
-
value = Attributes.new(value, &block) if block
|
57
|
-
attributes[name] = value
|
58
13
|
end
|
59
14
|
end
|
60
15
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'dry-types'
|
2
|
+
|
3
|
+
module Yuba
|
4
|
+
class Form < ::Reform::Form
|
5
|
+
module Coercion
|
6
|
+
module Types
|
7
|
+
include Dry::Types.module
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def property(name, options={}, &block)
|
12
|
+
super(name, options, &block).tap do
|
13
|
+
break unless options[:type]
|
14
|
+
coercing_setter!(name, options[:type])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def coercing_setter!(name, type)
|
19
|
+
class_name = type.to_s.classify
|
20
|
+
type_class = "Yuba::Form::Coercion::Types::Form::#{class_name}".constantize
|
21
|
+
|
22
|
+
mod = Module.new do
|
23
|
+
define_method("#{name}=") do |value|
|
24
|
+
super type_class.(value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
include mod
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.included(includer)
|
32
|
+
includer.extend ClassMethods
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Yuba::Form::MultiParameterAttributes
|
2
|
+
# TODO: implement this with parse_filter, so we don't have to manually walk through the hash, etc.
|
3
|
+
class DateTimeParamsFilter
|
4
|
+
def call(params)
|
5
|
+
params = params.dup # DISCUSS: not sure if that slows down form processing?
|
6
|
+
date_attributes = {}
|
7
|
+
|
8
|
+
params.each do |attribute, value|
|
9
|
+
if value.is_a?(Hash)
|
10
|
+
params[attribute] = call(value) # TODO: #validate should only handle local form params.
|
11
|
+
elsif matches = attribute.match(/^(\w+)\(.i\)$/)
|
12
|
+
date_attribute = matches[1]
|
13
|
+
date_attributes[date_attribute] = params_to_date(
|
14
|
+
params.delete("#{date_attribute}(1i)"),
|
15
|
+
params.delete("#{date_attribute}(2i)"),
|
16
|
+
params.delete("#{date_attribute}(3i)"),
|
17
|
+
params.delete("#{date_attribute}(4i)"),
|
18
|
+
params.delete("#{date_attribute}(5i)")
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
date_attributes.each do |attribute, date|
|
24
|
+
params[attribute] = date
|
25
|
+
end
|
26
|
+
params
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def params_to_date(year, month, day, hour, minute)
|
31
|
+
date_fields = [year, month, day].map!(&:to_i)
|
32
|
+
time_fields = [hour, minute].map!(&:to_i)
|
33
|
+
|
34
|
+
if date_fields.any?(&:zero?) || !Date.valid_date?(*date_fields)
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
if hour.blank? && minute.blank?
|
39
|
+
Date.new(*date_fields)
|
40
|
+
else
|
41
|
+
args = date_fields + time_fields
|
42
|
+
Time.zone ? Time.zone.local(*args) :
|
43
|
+
Time.new(*args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# this hooks into the format-specific #deserialize! method.
|
49
|
+
def deserialize!(params)
|
50
|
+
super DateTimeParamsFilter.new.call(params) # if params.is_a?(Hash) # this currently works for hash, only.
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Yuba
|
2
|
+
module Rendering
|
3
|
+
def render(*args)
|
4
|
+
view_model_hash = args.find { |arg| arg.is_a?(Hash) && arg[:view_model] }
|
5
|
+
@_view_model = view_model_hash[:view_model] if view_model_hash[:view_model]
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def view_assigns
|
10
|
+
super.merge(view_model_assigns)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def _protected_ivars
|
16
|
+
super.merge(:@_view_model)
|
17
|
+
end
|
18
|
+
|
19
|
+
def view_model_assigns
|
20
|
+
return {} unless @_view_model
|
21
|
+
# TODO: get all public methods between self and Yuba::ViewModel
|
22
|
+
# now get only in self
|
23
|
+
methods = @_view_model.public_methods(false)
|
24
|
+
methods.reject! do |method_name|
|
25
|
+
%i[call initialize].include?(method_name)
|
26
|
+
end
|
27
|
+
methods.inject({}) do |hash, method_name|
|
28
|
+
hash[method_name] = @_view_model.public_send(method_name)
|
29
|
+
hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/yuba/service.rb
CHANGED
@@ -1,37 +1,60 @@
|
|
1
1
|
module Yuba
|
2
2
|
class Service
|
3
|
+
class_attribute :_properties
|
4
|
+
self._properties = {}
|
5
|
+
|
3
6
|
class << self
|
4
7
|
def call(**args)
|
5
|
-
service = new
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
service = args.empty? ? new : new(**args)
|
9
|
+
service.call
|
10
|
+
service
|
11
|
+
end
|
12
|
+
|
13
|
+
def property(name, options = {})
|
14
|
+
_properties[name.to_sym] = options
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
|
-
def
|
16
|
-
|
18
|
+
def initialize(**args)
|
19
|
+
validate_arguments(args)
|
20
|
+
define_accessors(args)
|
21
|
+
success
|
22
|
+
end
|
23
|
+
|
24
|
+
def success
|
25
|
+
@_success = true
|
17
26
|
end
|
18
27
|
|
19
|
-
def
|
20
|
-
|
28
|
+
def fail!
|
29
|
+
@_success = false
|
21
30
|
end
|
22
31
|
|
23
|
-
def
|
24
|
-
|
32
|
+
def success?
|
33
|
+
@_success
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure?
|
37
|
+
!@_success
|
25
38
|
end
|
26
39
|
|
27
40
|
private
|
28
41
|
|
29
|
-
def
|
30
|
-
|
42
|
+
def validate_arguments(args)
|
43
|
+
args.each_key do |key|
|
44
|
+
if !_properties.has_key?(key.to_sym) && !_properties.dig(key.to_sym, :optional)
|
45
|
+
raise ArgumentError, "missing 'property :#{key}' in #{self.class.name} class"
|
46
|
+
end
|
47
|
+
end
|
31
48
|
end
|
32
49
|
|
33
|
-
def
|
34
|
-
|
50
|
+
def define_accessors(args)
|
51
|
+
args.each do |key, value|
|
52
|
+
public_method = _properties[key.to_sym][:public]
|
53
|
+
define_singleton_method key do
|
54
|
+
value
|
55
|
+
end
|
56
|
+
self.singleton_class.class_eval { private key.to_sym } unless public_method
|
57
|
+
end
|
35
58
|
end
|
36
59
|
end
|
37
60
|
end
|
data/lib/yuba/version.rb
CHANGED
data/lib/yuba/view_model.rb
CHANGED
@@ -1,26 +1,45 @@
|
|
1
1
|
module Yuba
|
2
2
|
class ViewModel
|
3
|
+
class_attribute :_properties
|
4
|
+
self._properties = {}
|
5
|
+
|
3
6
|
class << self
|
4
|
-
|
5
|
-
|
7
|
+
# You can register property to the class.
|
8
|
+
# Those registered by property need to be passed as arguments to the `initialize` except when `optional: true`
|
9
|
+
# is attached. You get `ArgumentError` if you don't pass `property` to `initialize`.
|
10
|
+
# Property is default to private. This means you can use it in internal the instance.
|
11
|
+
# If you it as public, use `public: true` option.
|
12
|
+
#
|
13
|
+
# property :name, public: true
|
14
|
+
# property :email, optional: true
|
15
|
+
def property(name, options = {})
|
16
|
+
_properties[name.to_sym] = options
|
6
17
|
end
|
7
18
|
end
|
8
19
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
args
|
20
|
+
def initialize(**args)
|
21
|
+
validate_arguments(args)
|
22
|
+
define_accessors(args)
|
12
23
|
end
|
13
24
|
|
14
|
-
|
15
|
-
@success
|
16
|
-
end
|
25
|
+
private
|
17
26
|
|
18
|
-
def
|
19
|
-
|
27
|
+
def validate_arguments(args)
|
28
|
+
args.each_key do |key|
|
29
|
+
if !_properties.has_key?(key.to_sym) && !_properties.dig(key.to_sym, :optional)
|
30
|
+
raise ArgumentError, "missing 'property :#{key}' in #{self.class.name} class"
|
31
|
+
end
|
32
|
+
end
|
20
33
|
end
|
21
34
|
|
22
|
-
def
|
23
|
-
|
35
|
+
def define_accessors(args)
|
36
|
+
args.each do |key, value|
|
37
|
+
public_method = _properties[key.to_sym][:public]
|
38
|
+
define_singleton_method key do
|
39
|
+
value
|
40
|
+
end
|
41
|
+
self.singleton_class.class_eval { private key.to_sym } unless public_method
|
42
|
+
end
|
24
43
|
end
|
25
44
|
end
|
26
45
|
end
|
metadata
CHANGED
@@ -1,29 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yuba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- willnet
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: reform-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-types
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
18
46
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
47
|
+
version: '0'
|
20
48
|
type: :runtime
|
21
49
|
prerelease: false
|
22
50
|
version_requirements: !ruby/object:Gem::Requirement
|
23
51
|
requirements:
|
24
|
-
- - "
|
52
|
+
- - ">="
|
25
53
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
54
|
+
version: '0'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: sqlite3
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +66,76 @@ dependencies:
|
|
38
66
|
- - ">="
|
39
67
|
- !ruby/object:Gem::Version
|
40
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: capybara
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: puma
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: selenium-webdriver
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: chromedriver-helper
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
41
139
|
description: Add New Layers to Rails. Form, Service, ViewModel.
|
42
140
|
email:
|
43
141
|
- netwillnet@gmail.com
|
@@ -48,11 +146,18 @@ files:
|
|
48
146
|
- MIT-LICENSE
|
49
147
|
- README.md
|
50
148
|
- Rakefile
|
149
|
+
- lib/generators/yuba/form/form_generator.rb
|
150
|
+
- lib/generators/yuba/form/templates/form.tt
|
151
|
+
- lib/generators/yuba/service/service_generator.rb
|
152
|
+
- lib/generators/yuba/service/templates/service.tt
|
153
|
+
- lib/generators/yuba/view_model/templates/view_model.tt
|
154
|
+
- lib/generators/yuba/view_model/view_model_generator.rb
|
51
155
|
- lib/tasks/crepe_tasks.rake
|
52
156
|
- lib/yuba.rb
|
53
157
|
- lib/yuba/form.rb
|
54
|
-
- lib/yuba/form/
|
55
|
-
- lib/yuba/form/
|
158
|
+
- lib/yuba/form/coercion.rb
|
159
|
+
- lib/yuba/form/multi_parameter_attributes.rb
|
160
|
+
- lib/yuba/rendering.rb
|
56
161
|
- lib/yuba/service.rb
|
57
162
|
- lib/yuba/version.rb
|
58
163
|
- lib/yuba/view_model.rb
|
@@ -71,12 +176,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
176
|
version: '0'
|
72
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
178
|
requirements:
|
74
|
-
- - "
|
179
|
+
- - ">="
|
75
180
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
181
|
+
version: '0'
|
77
182
|
requirements: []
|
78
183
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.6.
|
184
|
+
rubygems_version: 2.6.13
|
80
185
|
signing_key:
|
81
186
|
specification_version: 4
|
82
187
|
summary: Add New Layers to Rails
|
data/lib/yuba/form/attribute.rb
DELETED
data/lib/yuba/form/attributes.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Yuba
|
2
|
-
module Form
|
3
|
-
class Attributes
|
4
|
-
class_attribute :attributes
|
5
|
-
self.attributes = {}
|
6
|
-
|
7
|
-
def initialize(value)
|
8
|
-
yield if block_given?
|
9
|
-
deep_assign(value)
|
10
|
-
end
|
11
|
-
|
12
|
-
def attribute(name, type: string, &block)
|
13
|
-
mod = Module.new do
|
14
|
-
define_method(name) do
|
15
|
-
attributes[name.to_s]
|
16
|
-
end
|
17
|
-
define_method("#{name}=") do |value|
|
18
|
-
write_attribute(name.to_s, value, block)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
include mod
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def write_attribute(name, value, block)
|
27
|
-
# TODO: convert value by type of attribute
|
28
|
-
value = Attributes.new(value, &block) if block
|
29
|
-
attributes[name] = value
|
30
|
-
end
|
31
|
-
|
32
|
-
def deep_assign(value)
|
33
|
-
raise ArgumentError unless value.is_a? Hash
|
34
|
-
value.each do |k,v|
|
35
|
-
if v.is_a? Hash
|
36
|
-
deep_assign(v)
|
37
|
-
else
|
38
|
-
attributes[name.to_s] = v
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|