yuba 0.0.1.pre → 0.0.1
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 +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
|
+
[](https://travis-ci.org/willnet/yuba)
|
4
|
+
[](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
|