tramway 0.2.3 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eee7e8b57c93fd646e96a26e07e9dab81b6deee977c50c2ab34b1df93f48e96d
4
- data.tar.gz: 48d411dcce7d057eb867862f2b8410b5320bbf2dfdc47f5a0e06508f34049139
3
+ metadata.gz: 817cf3ad464278dbd553e1e6d48c740a85305ca7ad8e4caac6a3d2fecc87041a
4
+ data.tar.gz: c3b5dadac4b6283f251c5647cb1d5dd2703c858a3e2a4730e0a80424b7c71e1a
5
5
  SHA512:
6
- metadata.gz: dc78481a707c0688c774469549b8c1dc319adfe51f67cdd871b4b4751f03367206c674298c764a54110aa9c9b634082c6c844e1b97df0e9d2b2411fb536fa527
7
- data.tar.gz: 2bdf9eca337acd11afacb0fca442e6047b1b600d5b6a499bad31ad7522777edf0c2079c247491334a32eb3bb8682d54c78e596256b120c14a6c4a62593592150
6
+ metadata.gz: '079777145b30d2bf2695a14c71b77ef0470a5e29ddd4c0b2bcc43f14bf711e9f96d674bfa814b84eb7dda438167ddaa584717aa52039c2b1a2e8b787ac7e8719'
7
+ data.tar.gz: be3904286806a86296274d42026d11a00308e80eb5fa14e0f7e794fc78e70b70040a813f727c2723b7b87289b6ff355e068a30a3cbe2ea4bdd95ee9680ca0258
data/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Tramway
2
2
  Unite Ruby on Rails brilliance. Streamline development with Tramway.
3
3
 
4
+ * [Installation](https://github.com/Purple-Magic/tramway#installation)
5
+ * [Usage](https://github.com/Purple-Magic/tramway#usage)
6
+ * [Tramway Entities](https://github.com/Purple-Magic/tramway#tramway-entities)
7
+ * [Tramway Decorators](https://github.com/Purple-Magic/tramway#tramway-decorators)
8
+ * [Tramway Form](https://github.com/Purple-Magic/tramway#tramway-form)
9
+ * [Tramway Navbar](https://github.com/Purple-Magic/tramway#tramway-navbar)
10
+ * [Tailwind-styled forms](https://github.com/Purple-Magic/tramway#tailwind-styled-forms)
11
+
4
12
  ## Installation
5
13
  Add this line to your application's Gemfile:
6
14
 
@@ -43,10 +51,6 @@ Tramway.configure do |config|
43
51
  end
44
52
  ```
45
53
 
46
- ### Tailwind components
47
-
48
- Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
49
-
50
54
  ### Tramway Decorators
51
55
 
52
56
  Tramway provides convenient decorators for your objects. **NOTE:** This is not the decorator pattern in its usual representation.
@@ -97,6 +101,152 @@ def show
97
101
  end
98
102
  ```
99
103
 
104
+ ### Tramway Form
105
+
106
+ Tramway provides **convenient** form objects for Rails applications. List properties you want to change and the rules in Form classes. No controllers overloading.
107
+
108
+ *app/forms/user_form.rb
109
+ ```ruby
110
+ class UserForm < Tramway::BaseForm
111
+ properties :email, :password, :first_name, :last_name, :phone
112
+
113
+ def password=(value)
114
+ object.password = value if value.present?
115
+ end
116
+ end
117
+ ```
118
+
119
+ **Controllers without Tramway Form**
120
+
121
+ *app/controllers/users_controller.rb*
122
+ ```ruby
123
+ class UsersController < ApplicationController
124
+ def create
125
+ @user = User.new
126
+ if @user.save user_params
127
+ render :show
128
+ else
129
+ render :new
130
+ end
131
+ end
132
+
133
+ def update
134
+ @user = User.find params[:id]
135
+ if @user.save user_params
136
+ render :show
137
+ else
138
+ render :edit
139
+ end
140
+ end
141
+
142
+ private
143
+
144
+ def user_params
145
+ params[:user].permit(:email, :password, :first_name, :last_name, :phone)
146
+ end
147
+ end
148
+ ```
149
+
150
+ **Controllers with Tramway Form**
151
+
152
+ *app/controllers/users_controller.rb*
153
+ ```ruby
154
+ class UsersController < ApplicationController
155
+ def create
156
+ @user = tramway_form User.new
157
+ if @user.submit params[:user]
158
+ render :show
159
+ else
160
+ render :new
161
+ end
162
+ end
163
+
164
+ def update
165
+ @user = tramway_form User.find params[:id]
166
+ if @user.submit params[:user]
167
+ render :show
168
+ else
169
+ render :edit
170
+ end
171
+ end
172
+ end
173
+ ```
174
+
175
+ #### Implement Form objects for any case
176
+
177
+ *app/forms/user_updating_email_form.rb*
178
+ ```ruby
179
+ class UserUpdatingEmailForm < Tramway::BaseForm
180
+ properties :email
181
+ end
182
+ ```
183
+
184
+ *app/controllers/updating_emails_controller.rb*
185
+ ```ruby
186
+ def update
187
+ @user = UserUpdatingEmailForm.new User.find params[:id]
188
+ if @user.submit params[:user]
189
+ # success
190
+ else
191
+ # failure
192
+ end
193
+ end
194
+ ```
195
+
196
+ #### Create form namespaces
197
+
198
+ *app/forms/admin/user_form.rb*
199
+ ```ruby
200
+ class Admin::UserForm < Tramway::BaseForm
201
+ properties :email, :password, :first_name, :last_name, :etc
202
+ end
203
+ ```
204
+
205
+ *app/controllers/admin/users_controller.rb*
206
+ ```ruby
207
+ class Admin::UsersController < Admin::ApplicationController
208
+ def create
209
+ @user = tramway_form User.new, namespace: :admin
210
+ if @user.submit params[:user]
211
+ render :show
212
+ else
213
+ render :new
214
+ end
215
+ end
216
+
217
+ def update
218
+ @user = tramway_form User.find(params[:id]), namespace: :admin
219
+ if @user.submit params[:user]
220
+ render :show
221
+ else
222
+ render :edit
223
+ end
224
+ end
225
+ end
226
+ ```
227
+
228
+ ### Make flexible and extendable forms
229
+
230
+ Tramway Form properties are not mapped to a model. You're able to make extended forms.
231
+
232
+ *app/forms/user_form.rb*
233
+ ```ruby
234
+ class UserForm < Tramway::BaseForm
235
+ properties :email, :password, :full_name
236
+
237
+ # RULE: in case password is empty, don't save
238
+ def password=(value)
239
+ object.password = value if value.present?
240
+ end
241
+
242
+ # EXTENDED FIELD: full name
243
+ def full_name=(value)
244
+ object.first_name = value.split(' ').first
245
+ object.last_name = value.split(' ').last
246
+ end
247
+ end
248
+ ```
249
+
100
250
  ### Tramway Navbar
101
251
 
102
252
  Tramway provides DSL for rendering Tailwind Navgiation bar.
@@ -163,6 +313,30 @@ tramway_navbar title: 'Purple Magic' do |nav|
163
313
  end
164
314
  ```
165
315
 
316
+ ### Tailwind-styled forms
317
+
318
+ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
319
+
320
+ #### tramway_form_for
321
+
322
+ Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by default.
323
+
324
+ ```ruby
325
+ = tramway_form_for User.new do |f|
326
+ = f.text_field :text
327
+ = f.password_field :password
328
+ = f.file_field :file
329
+ = f.submit "Create User"
330
+ ```
331
+
332
+ will render [this](https://play.tailwindcss.com/xho3LfjKkK)
333
+
334
+ Available form helpers:
335
+ * text_field
336
+ * password_field
337
+ * file_field
338
+ * submit
339
+
166
340
  ## Contributing
167
341
 
168
342
  Install [lefthook](https://github.com/evilmartians/lefthook)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailwinds
4
+ module Form
5
+ # Provides Tailwind-styled forms
6
+ class Builder < Tramway::Views::FormBuilder
7
+ def text_field(attribute, **options, &)
8
+ input = super(attribute, **options.merge(class: text_input_class))
9
+ render(Tailwinds::Form::TextFieldComponent.new(input, attribute, object_name:, **options), &)
10
+ end
11
+
12
+ def password_field(attribute, **options, &)
13
+ input = super(attribute, **options.merge(class: text_input_class))
14
+ render(Tailwinds::Form::TextFieldComponent.new(input, attribute, object_name:, **options), &)
15
+ end
16
+
17
+ def file_field(attribute, **options, &)
18
+ input = super(attribute, **options.merge(class: :hidden))
19
+
20
+ render(Tailwinds::Form::FileFieldComponent.new(input, attribute, object_name:, **options), &)
21
+ end
22
+
23
+ def submit(action, **options, &)
24
+ render(Tailwinds::Form::SubmitButtonComponent.new(action, **options), &)
25
+ end
26
+
27
+ private
28
+
29
+ def text_input_class
30
+ 'w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:border-red-500'
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,4 @@
1
+ .mb-4
2
+ %label.inline-block.bg-blue-500.hover:bg-blue-700.text-white.font-bold.py-2.px-4.rounded.cursor-pointer.mt-4{ for: @for }
3
+ = @label
4
+ = @input
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailwinds
4
+ module Form
5
+ # Tailwind-styled file_field input
6
+ class FileFieldComponent < TailwindComponent
7
+ def initialize(input, attribute, object_name: nil, **options)
8
+ @label = options[:label] || attribute.to_s.capitalize
9
+ @for = "#{object_name}_#{attribute}"
10
+ @input = input
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ .flex.items-center.justify-between
2
+ %button.bg-red-500.hover:bg-red-700.text-white.font-bold.py-2.px-4.rounded.focus:outline-none.focus:shadow-outline{ type: :submit, name: :commit, **@options }
3
+ = @text
4
+ = @content
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailwinds
4
+ module Form
5
+ # Tailwind-styled submit button
6
+ class SubmitButtonComponent < TailwindComponent
7
+ def initialize(action, **options)
8
+ @options = options.except :type
9
+
10
+ @text = action.is_a?(String) ? action : action.to_s.capitalize
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ .mb-4
2
+ %label.block.text-gray-700.text-sm.font-bold.mb-2{ for: @for }
3
+ = @label
4
+ = @input
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tailwinds
4
+ module Form
5
+ # Tailwind-styled text field
6
+ class TextFieldComponent < TailwindComponent
7
+ def initialize(input, attribute, object_name: nil, **options)
8
+ @label = options[:label] || attribute.to_s.humanize
9
+ @for = "#{object_name}_#{attribute}"
10
+ @input = input
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ # Provides form object for Tramway
5
+ #
6
+ class BaseForm
7
+ attr_reader :object
8
+
9
+ %i[model_name to_key to_model errors attributes].each do |method_name|
10
+ delegate method_name, to: :object
11
+ end
12
+
13
+ def initialize(object)
14
+ @object = object
15
+ end
16
+
17
+ class << self
18
+ def property(attribute, _proc_obj = nil)
19
+ @properties ||= []
20
+ @properties << attribute
21
+
22
+ delegate attribute, to: :object
23
+ end
24
+
25
+ def properties(*attributes)
26
+ if attributes.any?
27
+ attributes.each do |attribute|
28
+ property(attribute)
29
+ end
30
+ else
31
+ @properties || []
32
+ end
33
+ end
34
+ end
35
+
36
+ def submit(params)
37
+ __submit params
38
+
39
+ object.save.tap do
40
+ __object
41
+ end
42
+ end
43
+
44
+ def submit!(params)
45
+ __submit params
46
+
47
+ object.save!.tap do
48
+ __object
49
+ end
50
+ end
51
+
52
+ def method_missing(method_name, *args)
53
+ if method_name.to_s.end_with?('=') && args.count == 1
54
+ object.public_send(method_name, args.first)
55
+ else
56
+ super
57
+ end
58
+ end
59
+
60
+ def respond_to_missing?(method_name, include_private = false)
61
+ method_name.to_s.end_with?('=') || super
62
+ end
63
+
64
+ private
65
+
66
+ def __submit(params)
67
+ self.class.properties.each do |attribute|
68
+ public_send("#{attribute}=", params[attribute])
69
+ end
70
+ end
71
+
72
+ def __object
73
+ object.persisted? ? object.reload : object
74
+ end
75
+ end
76
+ end
@@ -13,11 +13,23 @@ module Tramway
13
13
  loaded_class.include Tramway::Helpers::NavbarHelper
14
14
  end
15
15
 
16
+ ActiveSupport.on_load(:action_view) do |loaded_class|
17
+ require 'tramway/helpers/views_helper'
18
+
19
+ loaded_class.include Tramway::Helpers::ViewsHelper
20
+ end
21
+
16
22
  ActiveSupport.on_load(:action_controller) do |loaded_class|
17
23
  require 'tramway/helpers/decorate_helper'
18
24
 
19
25
  loaded_class.include Tramway::Helpers::DecorateHelper
20
26
  end
27
+
28
+ ActiveSupport.on_load(:action_controller) do |loaded_class|
29
+ require 'tramway/helpers/form_helper'
30
+
31
+ loaded_class.include Tramway::Helpers::FormHelper
32
+ end
21
33
  end
22
34
  end
23
35
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Forms
5
+ # Provides method to determine decorators classes
6
+ module ClassHelper
7
+ module_function
8
+
9
+ def form_class(object, form, namespace)
10
+ object_class = object.class
11
+
12
+ if form.present?
13
+ form
14
+ elsif namespace.present?
15
+ "#{namespace.to_s.camelize}::#{object_class}Form".constantize
16
+ else
17
+ "#{object_class}Form".constantize
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tramway/forms/class_helper'
4
+
5
+ module Tramway
6
+ module Helpers
7
+ # Provides methods into Rails ActionController
8
+ #
9
+ module FormHelper
10
+ def tramway_form(object, form: nil, namespace: nil)
11
+ Tramway::Forms::ClassHelper.form_class(object, form, namespace).new object
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,7 +4,7 @@ require 'tramway/navbar'
4
4
 
5
5
  module Tramway
6
6
  module Helpers
7
- # Providing navbar helpers for ActionView
7
+ # Provides navbar helpers for ActionView
8
8
  module NavbarHelper
9
9
  def tramway_navbar(**options)
10
10
  initialize_navbar
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Helpers
5
+ # Provides view-oriented helpers for ActionView
6
+ module ViewsHelper
7
+ def tramway_form_for(object, *args, **options, &)
8
+ form_for(object, *args, **options.merge(builder: Tailwinds::Form::Builder), &)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '0.2.3'
4
+ VERSION = '0.3.1'
5
5
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Views
5
+ # ActionView Form Builder helps us use ViewComponent as form helpers
6
+ class FormBuilder < ActionView::Helpers::FormBuilder
7
+ attr_reader :template
8
+
9
+ private
10
+
11
+ def render(component, &)
12
+ component.render_in(template, &)
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/tramway.rb CHANGED
@@ -4,7 +4,9 @@ require 'types'
4
4
  require 'tramway/version'
5
5
  require 'tramway/engine'
6
6
  require 'tramway/base_decorator'
7
+ require 'tramway/base_form'
7
8
  require 'tramway/config'
9
+ require 'tramway/views/form_builder'
8
10
  require 'view_component/compiler'
9
11
  require 'view_component/engine'
10
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tramway
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - kalashnikovisme
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-08-17 00:00:00.000000000 Z
12
+ date: 2023-10-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: dry-struct
@@ -93,6 +93,13 @@ files:
93
93
  - Rakefile
94
94
  - app/components/tailwind_component.html.haml
95
95
  - app/components/tailwind_component.rb
96
+ - app/components/tailwinds/form/builder.rb
97
+ - app/components/tailwinds/form/file_field_component.html.haml
98
+ - app/components/tailwinds/form/file_field_component.rb
99
+ - app/components/tailwinds/form/submit_button_component.html.haml
100
+ - app/components/tailwinds/form/submit_button_component.rb
101
+ - app/components/tailwinds/form/text_field_component.html.haml
102
+ - app/components/tailwinds/form/text_field_component.rb
96
103
  - app/components/tailwinds/nav/item_component.html.haml
97
104
  - app/components/tailwinds/nav/item_component.rb
98
105
  - app/components/tailwinds/navbar_component.html.haml
@@ -102,17 +109,22 @@ files:
102
109
  - lib/tasks/tramway_tasks.rake
103
110
  - lib/tramway.rb
104
111
  - lib/tramway/base_decorator.rb
112
+ - lib/tramway/base_form.rb
105
113
  - lib/tramway/config.rb
106
114
  - lib/tramway/configs/entities/route.rb
107
115
  - lib/tramway/configs/entity.rb
108
116
  - lib/tramway/decorators/class_helper.rb
109
117
  - lib/tramway/decorators/collection_decorator.rb
110
118
  - lib/tramway/engine.rb
119
+ - lib/tramway/forms/class_helper.rb
111
120
  - lib/tramway/helpers/decorate_helper.rb
121
+ - lib/tramway/helpers/form_helper.rb
112
122
  - lib/tramway/helpers/navbar_helper.rb
123
+ - lib/tramway/helpers/views_helper.rb
113
124
  - lib/tramway/navbar.rb
114
125
  - lib/tramway/utils/render.rb
115
126
  - lib/tramway/version.rb
127
+ - lib/tramway/views/form_builder.rb
116
128
  - lib/types.rb
117
129
  homepage: https://github.com/purple-magic/tramway
118
130
  licenses: