yuba 0.0.1.pre → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 065c02ba0b6ba7a96764c3557e3f3abad4e2252d
4
- data.tar.gz: 13c440a52f8042fcd001d6d1305e233184c8aca2
2
+ SHA256:
3
+ metadata.gz: 7d13a7bddc245ba124ce105b6827afb261d6268a417809a6bc7ec04e70cff0b9
4
+ data.tar.gz: c4769bdc11c239e2c99d848ab99f9b13309c5f6c4064b53b52b4087c025eeaa8
5
5
  SHA512:
6
- metadata.gz: 107fbf7894edb031119725bd8f9844d78e52dbc3fc9f763cc0b60a244f50868b45949b2ffec47847e92a780598ee5af07e0a835adbcc15e339868ded43b275b8
7
- data.tar.gz: c9494157393285ba6b41d231ef56338411c890b96711010278053d6fdb00d71a6f4626ff1b564c1ba6bcecfebb3ea89c14e1f943dbdf83d12298ba5dddb33a10
6
+ metadata.gz: 8337d0d4addebc3bd44412fd23d4433ebb6f17d53db5e63dcfe666b4dda6351de39450f9d48ef7fc225d62871b52d90082cefac7e6b705b38b185c1c2e9c7733
7
+ data.tar.gz: 77447d91b1a2d68dd7cbf44055188d5e2bb6ac45b3b8e17af5101b0ce04952f7c4accb25f394eca3e8ba4a5b51690faba9978c45619a42603a265a19acd3c040
data/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Yuba
2
2
 
3
- This gem is now under construction. It doesn't work now.
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
- ## Usage
18
+ It is convenient to use them in combination, but you can use them even by themselves.
12
19
 
13
- How to use my plugin.
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,217 @@ 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
- Or install it yourself as:
28
- ```bash
29
- $ gem install yuba
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 < ApplicationController
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 < ApplicationController
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
+ end
182
+ ```
183
+
184
+ ```ruby
185
+ class Artist::CreateService < Yuba::Service
186
+ property :params
187
+
188
+ def call
189
+ if form.validate(params)
190
+ form.save
191
+ else
192
+ fail!
193
+ end
194
+ end
195
+
196
+ def view_model
197
+ Artist::CreateViewModel.new(form: form)
198
+ end
199
+
200
+ private
201
+
202
+ def form
203
+ @form ||= ArtistForm.new(Artist.new)
204
+ end
205
+ end
206
+ ```
207
+
208
+ ```ruby
209
+ class ArtistForm < Yuba::Form
210
+ property :name
211
+
212
+ validates :name, presence: true, length: { maximum: 100 }
213
+ end
214
+ ```
215
+
216
+ ```ruby
217
+ class Artist::CreateViewModel < Yuba::ViewModel
218
+ property :form, public: true
219
+ end
220
+ ```
221
+
222
+ ## generators
223
+
224
+ You can use generators.
225
+
226
+ ```
227
+ rails generate yuba:service create_artist
228
+ rails generate yuba:form artist
229
+ rails generate yuba:view_model artist_index
30
230
  ```
31
231
 
32
232
  ## Contributing
33
- Contribution directions go here.
233
+
234
+ You can try to test by doing as following
235
+
236
+ ```
237
+ git clone https://github.com/willnet/yuba.git
238
+ cd yuba
239
+ bundle
240
+ bundle exec rake
241
+ ```
34
242
 
35
243
  ## License
36
244
  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 FormGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def generate_form
6
+ template 'form.tt', File.join('app/forms', class_path, "#{file_name}_form.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Form < Yuba::Form
3
+ end
4
+ <% end -%>
@@ -0,0 +1,9 @@
1
+ module Yuba
2
+ class ServiceGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def generate_service
6
+ template 'service.tt', File.join('app/services', class_path, "#{file_name}_service.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Service < Yuba::Service
3
+ def call
4
+ end
5
+ end
6
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>ViewModel < Yuba::ViewModel
3
+ end
4
+ <% end -%>
@@ -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
@@ -1,5 +1,12 @@
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'
5
8
  end
9
+
10
+ ActiveSupport.on_load(:action_controller) do
11
+ ActionController::Base.include(Yuba::ViewModel::Rendering)
12
+ end
@@ -1,60 +1,15 @@
1
- module Yuba
2
- class Form
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
- # TODO: reformのようにネストできるようにしたい
13
- def attribute(name, type: 'string', &block)
14
- mod = Module.new do
15
- define_method(name) do
16
- attributes[name.to_s]
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
@@ -1,37 +1,70 @@
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
- return_value = args.present? ? service.call(**args) : service.call
7
- if return_value.respond_to?(:success?)
8
- return_value
9
- else
10
- result.success(form: service.form)
11
- end
8
+ service = args.empty? ? new : new(**args)
9
+ service.call
10
+ service
11
+ end
12
+
13
+ def property(name, options = {})
14
+ self._properties = _properties.merge(name.to_sym => options)
12
15
  end
13
16
  end
14
17
 
15
- def build_form(**args)
16
- form_class.build(**args)
18
+ def initialize(**args)
19
+ validate_arguments(args)
20
+ define_accessors(args)
21
+ success
22
+ end
23
+
24
+ def success
25
+ @_success = true
26
+ end
27
+
28
+ def fail!
29
+ @_success = false
17
30
  end
18
31
 
19
- def form_class
20
- Object.const_get(form_class_name)
32
+ def success?
33
+ @_success
21
34
  end
22
35
 
23
- def view_model_class
24
- Object.const_get(form_class_name)
36
+ def failure?
37
+ !@_success
25
38
  end
26
39
 
27
40
  private
28
41
 
29
- def form_class_name
30
- self.class.name.sub(/::.+Service/, 'Form')
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
48
+
49
+ required_keys = _required_properties.keys
50
+ missing_keys = required_keys - args.keys
51
+ unless missing_keys.empty?
52
+ raise ArgumentError, "missing required arguments: #{missing_keys.join(',')}"
53
+ end
54
+ end
55
+
56
+ def define_accessors(args)
57
+ args.each do |key, value|
58
+ public_method = _properties[key.to_sym][:public]
59
+ define_singleton_method key do
60
+ value
61
+ end
62
+ self.singleton_class.class_eval { private key.to_sym } unless public_method
63
+ end
31
64
  end
32
65
 
33
- def view_model_class_name
34
- self.class.name.sub(/Service\z/, 'ViewModel')
66
+ def _required_properties
67
+ _properties.reject { |_, value| value[:optional] }
35
68
  end
36
69
  end
37
70
  end
@@ -1,3 +1,3 @@
1
1
  module Yuba
2
- VERSION = '0.0.1.pre'
2
+ VERSION = '0.0.5'
3
3
  end
@@ -1,26 +1,50 @@
1
1
  module Yuba
2
2
  class ViewModel
3
+ autoload :Rendering, 'yuba/view_model/rendering'
4
+
5
+ class_attribute :_properties
6
+ self._properties = {}
7
+
3
8
  class << self
4
- def success(**args)
5
- new(args.merge(success: true))
9
+ # You can register property to the class.
10
+ # Those registered by property need to be passed as arguments to the `initialize` except when `optional: true`
11
+ # is attached. You get `ArgumentError` if you don't pass `property` to `initialize`.
12
+ # Property is default to private. This means you can use it in internal the instance.
13
+ # If you it as public, use `public: true` option.
14
+ #
15
+ # property :name, public: true
16
+ # property :email, optional: true
17
+ def property(name, options = {})
18
+ self._properties = _properties.merge(name.to_sym => options)
6
19
  end
7
20
  end
8
21
 
9
- def initialize(success: true, **args)
10
- @success = success
11
- args.each { |k,v| self.class.send(:define_method, k) { v } }
22
+ def initialize(**args)
23
+ @_args = args
24
+ validate_arguments
25
+ define_accessors
12
26
  end
13
27
 
14
- def success?
15
- @success
16
- end
28
+ private
17
29
 
18
- def failure?
19
- !@success
30
+ attr_reader :_args
31
+
32
+ def validate_arguments
33
+ _args.each_key do |key|
34
+ if !_properties.has_key?(key.to_sym) && !_properties.dig(key.to_sym, :optional)
35
+ raise ArgumentError, "missing 'property :#{key}' in #{self.class.name} class"
36
+ end
37
+ end
20
38
  end
21
39
 
22
- def to_model
23
- form
40
+ def define_accessors
41
+ _args.each do |key, value|
42
+ public_method = _properties[key.to_sym][:public]
43
+ define_singleton_method key do
44
+ value
45
+ end
46
+ self.singleton_class.class_eval { private key.to_sym } unless public_method
47
+ end
24
48
  end
25
49
  end
26
50
  end
@@ -0,0 +1,38 @@
1
+ module Yuba
2
+ class ViewModel
3
+ module Rendering
4
+ def render(*args)
5
+ view_model_hash = args.find { |arg| arg.is_a?(Hash) && arg[:view_model] }
6
+ @_view_model = view_model_hash[:view_model] if view_model_hash && view_model_hash[:view_model]
7
+ super
8
+ end
9
+
10
+ def view_assigns
11
+ super.merge(view_model_assigns)
12
+ end
13
+
14
+ private
15
+
16
+ def _protected_ivars
17
+ super.merge(:@_view_model)
18
+ end
19
+
20
+ def view_model_assigns
21
+ return {} unless defined?(@_view_model)
22
+ methods = @_view_model.public_methods(false)
23
+ methods.reject! do |method_name|
24
+ %i[initialize].include?(method_name) ||
25
+ !valid_variable_name?(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
+
33
+ def valid_variable_name?(name)
34
+ name.match?(/\A[_a-z]\w*\z/)
35
+ end
36
+ end
37
+ end
38
+ 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.pre
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - willnet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-12 00:00:00.000000000 Z
11
+ date: 2021-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.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: 5.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
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
45
  - - "~>"
18
46
  - !ruby/object:Gem::Version
19
- version: 5.1.0
47
+ version: 0.12.2
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: 5.1.0
54
+ version: 0.12.2
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: webdrivers
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,14 +146,20 @@ files:
48
146
  - MIT-LICENSE
49
147
  - README.md
50
148
  - Rakefile
51
- - lib/tasks/crepe_tasks.rake
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
52
155
  - lib/yuba.rb
53
156
  - lib/yuba/form.rb
54
- - lib/yuba/form/attribute.rb
55
- - lib/yuba/form/attributes.rb
157
+ - lib/yuba/form/coercion.rb
158
+ - lib/yuba/form/multi_parameter_attributes.rb
56
159
  - lib/yuba/service.rb
57
160
  - lib/yuba/version.rb
58
161
  - lib/yuba/view_model.rb
162
+ - lib/yuba/view_model/rendering.rb
59
163
  homepage: https://github.com/willnet/yuba
60
164
  licenses:
61
165
  - MIT
@@ -71,12 +175,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
175
  version: '0'
72
176
  required_rubygems_version: !ruby/object:Gem::Requirement
73
177
  requirements:
74
- - - ">"
178
+ - - ">="
75
179
  - !ruby/object:Gem::Version
76
- version: 1.3.1
180
+ version: '0'
77
181
  requirements: []
78
- rubyforge_project:
79
- rubygems_version: 2.6.11
182
+ rubygems_version: 3.1.2
80
183
  signing_key:
81
184
  specification_version: 4
82
185
  summary: Add New Layers to Rails
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :yuba do
3
- # # Task goes here
4
- # end
@@ -1,9 +0,0 @@
1
- module Yuba
2
- class Form
3
- class Attribute
4
- def initialize(name)
5
- @name = name
6
- end
7
- end
8
- end
9
- end
@@ -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