tramway 0.2.2 → 0.3

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: 12b9bb73f91f5c694ee64efaa36d66a5ee68c6b41066a5e775b42e4ba81678d4
4
- data.tar.gz: 79c240ff539d4762fb8a2c4b3fe29ff05805c2699e12225d53038fafb53c5a1d
3
+ metadata.gz: 5e8751e6e662061508bb687b258c13f3dcb40460344959595a66c998608e38af
4
+ data.tar.gz: 66076bba6be9af35c2e787bf43e8e6cb00877bd5f5b53cf4b70ce37a09f78c2b
5
5
  SHA512:
6
- metadata.gz: 5ccd8cdeb8bb8b9df08d4885ff473e68ef7a29f5980460050e52db4d7b7b758da170cabece248f78589dbc102d47f1ae4c3ee1410d50d8103cbb4ffc549d0a2e
7
- data.tar.gz: 58c752011aa51d3c0afd9e074380411657a390b0a09568226de9d4c38b033d1b9b23f172b27af2a3ae137bc342185fad3736085412025d66cac4dab68e4ff994
6
+ metadata.gz: aec595653662af5dfe38f8d402dd799d8da2ad77ba8c3e032aba22c56020467f9b4ee1f701a07e7477ecbd34ff7725c32fac18a6a359513e064dbbdc567d703c
7
+ data.tar.gz: 5e1799a4d4290ac7bf5e9bd8c1fe524119eb4449ffe0ddeccb3ecf934343160672572c22e834f76a7bebe522d4ca226aa08ce8336ba1f56f88dc53fe692eba72
data/README.md CHANGED
@@ -1,6 +1,13 @@
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
+
4
11
  ## Installation
5
12
  Add this line to your application's Gemfile:
6
13
 
@@ -26,9 +33,22 @@ end
26
33
 
27
34
  By default, links to the Tramway Entities index page are rendered in [Tramway Navbar](https://github.com/Purple-Magic/tramway#tramway-navbar).
28
35
 
29
- ### Tailwind components
36
+ #### Define entities with options
30
37
 
31
- Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
38
+ Tramway Entity supports several options that are used in different features.
39
+
40
+ **route**
41
+
42
+ *config/initializers/tramway.rb*
43
+ ```ruby
44
+ Tramway.configure do |config|
45
+ config.entities = [
46
+ { name: :user, route: { namespace: :admin } }, # `admin_users_path` link in the Tramway Navbar
47
+ { name: :podcast, route: { route_method: :shows } }, # `shows_path` link in the Tramway Navbar
48
+ { name: :episodes, route: { namespace: :podcasts, route_method: :episodes } }, # `podcasts_episodes_path` link in the Tramway Navbar
49
+ ]
50
+ end
51
+ ```
32
52
 
33
53
  ### Tramway Decorators
34
54
 
@@ -80,6 +100,152 @@ def show
80
100
  end
81
101
  ```
82
102
 
103
+ ### Tramway Form
104
+
105
+ Tramway provides **convenient** form objects for Rails applications. List properties you want to change and the rules in Form classes. No controllers overloading.
106
+
107
+ *app/forms/user_form.rb
108
+ ```ruby
109
+ class UserForm < Tramway::BaseForm
110
+ properties :email, :password, :first_name, :last_name, :phone
111
+
112
+ def password=(value)
113
+ object.password = value if value.present?
114
+ end
115
+ end
116
+ ```
117
+
118
+ **Controllers without Tramway Form**
119
+
120
+ *app/controllers/users_controller.rb*
121
+ ```ruby
122
+ class UsersController < ApplicationController
123
+ def create
124
+ @user = User.new
125
+ if @user.save user_params
126
+ render :show
127
+ else
128
+ render :new
129
+ end
130
+ end
131
+
132
+ def update
133
+ @user = User.find params[:id]
134
+ if @user.save user_params
135
+ render :show
136
+ else
137
+ render :edit
138
+ end
139
+ end
140
+
141
+ private
142
+
143
+ def user_params
144
+ params[:user].permit(:email, :password, :first_name, :last_name, :phone)
145
+ end
146
+ end
147
+ ```
148
+
149
+ **Controllers with Tramway Form**
150
+
151
+ *app/controllers/users_controller.rb*
152
+ ```ruby
153
+ class UsersController < ApplicationController
154
+ def create
155
+ @user = tramway_form User.new
156
+ if @user.submit params[:user]
157
+ render :show
158
+ else
159
+ render :new
160
+ end
161
+ end
162
+
163
+ def update
164
+ @user = tramway_form User.find params[:id]
165
+ if @user.submit params[:user]
166
+ render :show
167
+ else
168
+ render :edit
169
+ end
170
+ end
171
+ end
172
+ ```
173
+
174
+ #### Implement Form objects for any case
175
+
176
+ *app/forms/user_updating_email_form.rb*
177
+ ```ruby
178
+ class UserUpdatingEmailForm < Tramway::BaseForm
179
+ properties :email
180
+ end
181
+ ```
182
+
183
+ *app/controllers/updating_emails_controller.rb*
184
+ ```ruby
185
+ def update
186
+ @user = UserUpdatingEmailForm.new User.find params[:id]
187
+ if @user.submit params[:user]
188
+ # success
189
+ else
190
+ # failure
191
+ end
192
+ end
193
+ ```
194
+
195
+ #### Create form namespaces
196
+
197
+ *app/forms/admin/user_form.rb*
198
+ ```ruby
199
+ class Admin::UserForm < Tramway::BaseForm
200
+ properties :email, :password, :first_name, :last_name, :etc
201
+ end
202
+ ```
203
+
204
+ *app/controllers/admin/users_controller.rb*
205
+ ```ruby
206
+ class Admin::UsersController < Admin::ApplicationController
207
+ def create
208
+ @user = tramway_form User.new, namespace: :admin
209
+ if @user.submit params[:user]
210
+ render :show
211
+ else
212
+ render :new
213
+ end
214
+ end
215
+
216
+ def update
217
+ @user = tramway_form User.find(params[:id]), namespace: :admin
218
+ if @user.submit params[:user]
219
+ render :show
220
+ else
221
+ render :edit
222
+ end
223
+ end
224
+ end
225
+ ```
226
+
227
+ ### Make flexible and extendable forms
228
+
229
+ Tramway Form properties are not mapped to a model. You're able to make extended forms.
230
+
231
+ *app/forms/user_form.rb*
232
+ ```ruby
233
+ class UserForm < Tramway::BaseForm
234
+ properties :email, :password, :full_name
235
+
236
+ # RULE: in case password is empty, don't save
237
+ def password=(value)
238
+ object.password = value if value.present?
239
+ end
240
+
241
+ # EXTENDED FIELD: full name
242
+ def full_name=(value)
243
+ object.first_name = value.split(' ').first
244
+ object.last_name = value.split(' ').last
245
+ end
246
+ end
247
+ ```
248
+
83
249
  ### Tramway Navbar
84
250
 
85
251
  Tramway provides DSL for rendering Tailwind Navgiation bar.
@@ -146,6 +312,10 @@ tramway_navbar title: 'Purple Magic' do |nav|
146
312
  end
147
313
  ```
148
314
 
315
+ ### Tailwind components
316
+
317
+ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are implemented with [ViewComponent](https://github.com/viewcomponent/view_component).
318
+
149
319
  ## Contributing
150
320
 
151
321
  Install [lefthook](https://github.com/evilmartians/lefthook)
@@ -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
@@ -15,7 +15,9 @@ module Tramway
15
15
 
16
16
  def entities=(collection)
17
17
  @entities = collection.map do |entity|
18
- Tramway::Configs::Entity.new(name: entity)
18
+ entity_options = entity.is_a?(Hash) ? entity : { name: entity }
19
+
20
+ Tramway::Configs::Entity.new(**entity_options)
19
21
  end
20
22
  end
21
23
 
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ module Configs
5
+ module Entities
6
+ # Route struct describes rules for route management
7
+ #
8
+ class Route < Dry::Struct
9
+ attribute? :namespace, Types::Coercible::String
10
+ attribute? :route_method, Types::Coercible::String
11
+
12
+ def helper_method_by(underscored_name)
13
+ "#{[namespace, route_method || underscored_name].compact.join('_')}_path"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,24 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tramway/configs/entities/route'
4
+
3
5
  module Tramway
4
6
  module Configs
5
- # Tramway is entity based framework
6
- #
7
- class Entity
8
- attr_reader :name
7
+ # Tramway is an entity-based framework
8
+ class Entity < Dry::Struct
9
+ attribute :name, Types::Coercible::String
10
+ attribute? :route, Tramway::Configs::Entities::Route
9
11
 
10
- def initialize(name:)
11
- @name = name.to_s
12
+ def routes
13
+ OpenStruct.new index: Rails.application.routes.url_helpers.public_send(route_helper_method)
12
14
  end
13
15
 
14
- def routes
15
- underscored_name = name.parameterize.pluralize.underscore
16
+ def human_name
17
+ options = if model_class.present?
18
+ model_name = model_class.model_name.human
19
+ { single: model_name, plural: model_name.pluralize }
20
+ else
21
+ { single: name.capitalize, plural: name.pluralize.capitalize }
22
+ end
23
+ OpenStruct.new(**options)
24
+ end
25
+
26
+ private
16
27
 
17
- OpenStruct.new index: Rails.application.routes.url_helpers.public_send("#{underscored_name}_path")
28
+ def model_class
29
+ name.camelize.constantize
30
+ rescue StandardError
31
+ nil
18
32
  end
19
33
 
20
- def human_name
21
- OpenStruct.new single: name.capitalize, plural: name.pluralize.capitalize
34
+ def route_helper_method
35
+ underscored_name = name.parameterize.pluralize.underscore
36
+
37
+ if route.present?
38
+ route.helper_method_by(underscored_name)
39
+ else
40
+ "#{underscored_name}_path"
41
+ end
22
42
  end
23
43
  end
24
44
  end
@@ -18,6 +18,12 @@ module Tramway
18
18
 
19
19
  loaded_class.include Tramway::Helpers::DecorateHelper
20
20
  end
21
+
22
+ ActiveSupport.on_load(:action_controller) do |loaded_class|
23
+ require 'tramway/helpers/form_helper'
24
+
25
+ loaded_class.include Tramway::Helpers::FormHelper
26
+ end
21
27
  end
22
28
  end
23
29
  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
@@ -51,8 +51,6 @@ module Tramway
51
51
  filling_side :left
52
52
 
53
53
  entities.each do |entity|
54
- entity.to_s.pluralize
55
-
56
54
  item entity.human_name.plural, entity.routes.index
57
55
  end
58
56
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3'
5
5
  end
data/lib/tramway.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'types'
3
4
  require 'tramway/version'
4
5
  require 'tramway/engine'
5
6
  require 'tramway/base_decorator'
7
+ require 'tramway/base_form'
6
8
  require 'tramway/config'
7
9
  require 'view_component/compiler'
8
10
  require 'view_component/engine'
data/lib/types.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-struct'
4
+
5
+ # We need because of this https://dry-rb.org/gems/dry-struct/1.6/recipes/
6
+ module Types
7
+ include Dry.Types()
8
+ end
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.2
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - kalashnikovisme
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-07-26 00:00:00.000000000 Z
12
+ date: 2023-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dry-struct
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: haml-rails
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -88,16 +102,21 @@ files:
88
102
  - lib/tasks/tramway_tasks.rake
89
103
  - lib/tramway.rb
90
104
  - lib/tramway/base_decorator.rb
105
+ - lib/tramway/base_form.rb
91
106
  - lib/tramway/config.rb
107
+ - lib/tramway/configs/entities/route.rb
92
108
  - lib/tramway/configs/entity.rb
93
109
  - lib/tramway/decorators/class_helper.rb
94
110
  - lib/tramway/decorators/collection_decorator.rb
95
111
  - lib/tramway/engine.rb
112
+ - lib/tramway/forms/class_helper.rb
96
113
  - lib/tramway/helpers/decorate_helper.rb
114
+ - lib/tramway/helpers/form_helper.rb
97
115
  - lib/tramway/helpers/navbar_helper.rb
98
116
  - lib/tramway/navbar.rb
99
117
  - lib/tramway/utils/render.rb
100
118
  - lib/tramway/version.rb
119
+ - lib/types.rb
101
120
  homepage: https://github.com/purple-magic/tramway
102
121
  licenses:
103
122
  - MIT