phlexible 0.1.0 → 0.3.0

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: d6c45035fcfe50f425a2876e79f5973399b74b76f5923357dd02c355575d0eac
4
- data.tar.gz: 49e7ddc371aaad6e53316cdd4aa5bb0bfb76cda8f6fa1052779e40306d1e339a
3
+ metadata.gz: 1d6d20a51dd488d65ba2a2ca84ffd702e5cff5505dce12595cdd1d2ca3f0c8b6
4
+ data.tar.gz: 12bdc3b31f359f5e974ba21d7cb154145c3e0444604c6a20cf706d94eb6a07f8
5
5
  SHA512:
6
- metadata.gz: 9149698fef1b20d16ca297db60e847172a7454dcab4a53e2798a9cbe38f04ab5b87124453861c312f8002365a895b4e97b76494541568cd3c8c1714c5d99cf4b
7
- data.tar.gz: 7e4782383a6f3f542b460739c2e3ed7d27dbf677ab2dab2b73794bb12f0298e19833e63e329ab744e510a750f0db3465546ae5a6704503755c6fa54df034ec48
6
+ metadata.gz: '09db42fc189ffefa64ca54bdedf9e171d0bf9d3084b4bc89a1c18953141f4fbad978e1a10b0d9d81a522df5ddf633ddca6f34aff214f2e69542f5ca197f232fa'
7
+ data.tar.gz: 0bb3d5026764d1366fe31f1b57f05e8c0ec8eeb24947c73c85448ecb4e9f7f9fcf6a0fd425e3150548e34525405c483a86c0725df8f03690d5df0fff225f1768
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.7
2
+ TargetRubyVersion: 3.0
3
3
  SuggestExtensions: false
4
4
  NewCops: enable
5
5
 
@@ -14,3 +14,5 @@ Lint/ConstantDefinitionInBlock:
14
14
  Style/ClassAndModuleChildren:
15
15
  Exclude:
16
16
  - fixtures/**/*
17
+ Metrics/MethodLength:
18
+ Max: 15
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  gem 'combustion'
9
+ gem 'phlex-testing-nokogiri'
9
10
  gem 'rake', '~> 13.0'
10
11
  gem 'rubocop', '~> 1.21'
11
- gem 'sus', '~> 0.16.0'
12
+ gem 'sus', '~> 0.20.0'
data/Gemfile.lock CHANGED
@@ -1,89 +1,92 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- phlexible (0.1.0)
5
- phlex (~> 1.0)
6
- phlex-rails (~> 0.4)
4
+ phlexible (0.2.0)
5
+ phlex (~> 1.5.1)
6
+ phlex-rails (~> 0.8.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actioncable (7.0.4)
12
- actionpack (= 7.0.4)
13
- activesupport (= 7.0.4)
11
+ actioncable (7.0.4.2)
12
+ actionpack (= 7.0.4.2)
13
+ activesupport (= 7.0.4.2)
14
14
  nio4r (~> 2.0)
15
15
  websocket-driver (>= 0.6.1)
16
- actionmailbox (7.0.4)
17
- actionpack (= 7.0.4)
18
- activejob (= 7.0.4)
19
- activerecord (= 7.0.4)
20
- activestorage (= 7.0.4)
21
- activesupport (= 7.0.4)
16
+ actionmailbox (7.0.4.2)
17
+ actionpack (= 7.0.4.2)
18
+ activejob (= 7.0.4.2)
19
+ activerecord (= 7.0.4.2)
20
+ activestorage (= 7.0.4.2)
21
+ activesupport (= 7.0.4.2)
22
22
  mail (>= 2.7.1)
23
23
  net-imap
24
24
  net-pop
25
25
  net-smtp
26
- actionmailer (7.0.4)
27
- actionpack (= 7.0.4)
28
- actionview (= 7.0.4)
29
- activejob (= 7.0.4)
30
- activesupport (= 7.0.4)
26
+ actionmailer (7.0.4.2)
27
+ actionpack (= 7.0.4.2)
28
+ actionview (= 7.0.4.2)
29
+ activejob (= 7.0.4.2)
30
+ activesupport (= 7.0.4.2)
31
31
  mail (~> 2.5, >= 2.5.4)
32
32
  net-imap
33
33
  net-pop
34
34
  net-smtp
35
35
  rails-dom-testing (~> 2.0)
36
- actionpack (7.0.4)
37
- actionview (= 7.0.4)
38
- activesupport (= 7.0.4)
36
+ actionpack (7.0.4.2)
37
+ actionview (= 7.0.4.2)
38
+ activesupport (= 7.0.4.2)
39
39
  rack (~> 2.0, >= 2.2.0)
40
40
  rack-test (>= 0.6.3)
41
41
  rails-dom-testing (~> 2.0)
42
42
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
43
- actiontext (7.0.4)
44
- actionpack (= 7.0.4)
45
- activerecord (= 7.0.4)
46
- activestorage (= 7.0.4)
47
- activesupport (= 7.0.4)
43
+ actiontext (7.0.4.2)
44
+ actionpack (= 7.0.4.2)
45
+ activerecord (= 7.0.4.2)
46
+ activestorage (= 7.0.4.2)
47
+ activesupport (= 7.0.4.2)
48
48
  globalid (>= 0.6.0)
49
49
  nokogiri (>= 1.8.5)
50
- actionview (7.0.4)
51
- activesupport (= 7.0.4)
50
+ actionview (7.0.4.2)
51
+ activesupport (= 7.0.4.2)
52
52
  builder (~> 3.1)
53
53
  erubi (~> 1.4)
54
54
  rails-dom-testing (~> 2.0)
55
55
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
56
- activejob (7.0.4)
57
- activesupport (= 7.0.4)
56
+ activejob (7.0.4.2)
57
+ activesupport (= 7.0.4.2)
58
58
  globalid (>= 0.3.6)
59
- activemodel (7.0.4)
60
- activesupport (= 7.0.4)
61
- activerecord (7.0.4)
62
- activemodel (= 7.0.4)
63
- activesupport (= 7.0.4)
64
- activestorage (7.0.4)
65
- actionpack (= 7.0.4)
66
- activejob (= 7.0.4)
67
- activerecord (= 7.0.4)
68
- activesupport (= 7.0.4)
59
+ activemodel (7.0.4.2)
60
+ activesupport (= 7.0.4.2)
61
+ activerecord (7.0.4.2)
62
+ activemodel (= 7.0.4.2)
63
+ activesupport (= 7.0.4.2)
64
+ activestorage (7.0.4.2)
65
+ actionpack (= 7.0.4.2)
66
+ activejob (= 7.0.4.2)
67
+ activerecord (= 7.0.4.2)
68
+ activesupport (= 7.0.4.2)
69
69
  marcel (~> 1.0)
70
70
  mini_mime (>= 1.1.0)
71
- activesupport (7.0.4)
71
+ activesupport (7.0.4.2)
72
72
  concurrent-ruby (~> 1.0, >= 1.0.2)
73
73
  i18n (>= 1.6, < 2)
74
74
  minitest (>= 5.1)
75
75
  tzinfo (~> 2.0)
76
76
  ast (2.4.2)
77
77
  builder (3.2.4)
78
+ cgi (0.3.6)
78
79
  combustion (1.3.7)
79
80
  activesupport (>= 3.0.0)
80
81
  railties (>= 3.0.0)
81
82
  thor (>= 0.14.6)
82
- concurrent-ruby (1.1.10)
83
+ concurrent-ruby (1.2.2)
83
84
  crass (1.0.6)
84
85
  date (3.3.3)
86
+ erb (4.0.2)
87
+ cgi (>= 0.3.3)
85
88
  erubi (1.12.0)
86
- globalid (1.0.0)
89
+ globalid (1.1.0)
87
90
  activesupport (>= 5.0)
88
91
  i18n (1.12.0)
89
92
  concurrent-ruby (~> 1.0)
@@ -91,7 +94,7 @@ GEM
91
94
  loofah (2.19.1)
92
95
  crass (~> 1.0.2)
93
96
  nokogiri (>= 1.5.9)
94
- mail (2.8.0)
97
+ mail (2.8.1)
95
98
  mini_mime (>= 0.1.1)
96
99
  net-imap
97
100
  net-pop
@@ -99,8 +102,7 @@ GEM
99
102
  marcel (1.0.2)
100
103
  method_source (1.0.0)
101
104
  mini_mime (1.1.2)
102
- mini_portile2 (2.8.1)
103
- minitest (5.17.0)
105
+ minitest (5.18.0)
104
106
  net-imap (0.3.4)
105
107
  date
106
108
  net-protocol
@@ -111,75 +113,83 @@ GEM
111
113
  net-smtp (0.3.3)
112
114
  net-protocol
113
115
  nio4r (2.5.8)
114
- nokogiri (1.13.10)
115
- mini_portile2 (~> 2.8.0)
116
+ nokogiri (1.14.2-arm64-darwin)
117
+ racc (~> 1.4)
118
+ nokogiri (1.14.2-x86_64-darwin)
119
+ racc (~> 1.4)
120
+ nokogiri (1.14.2-x86_64-linux)
116
121
  racc (~> 1.4)
117
122
  parallel (1.22.1)
118
- parser (3.2.0.0)
123
+ parser (3.2.1.0)
119
124
  ast (~> 2.4.1)
120
- phlex (1.1.0)
125
+ phlex (1.5.1)
126
+ concurrent-ruby (~> 1.2)
127
+ erb (>= 4)
121
128
  zeitwerk (~> 2.6)
122
- phlex-rails (0.4.2)
123
- phlex (>= 1, < 2)
129
+ phlex-rails (0.8.0)
130
+ phlex (~> 1.5)
124
131
  rails (>= 6.1, < 8)
125
- zeitwerk (~> 2)
132
+ zeitwerk (~> 2.6)
133
+ phlex-testing-nokogiri (0.1.0)
134
+ nokogiri (~> 1.13)
135
+ phlex (>= 0.5)
126
136
  racc (1.6.2)
127
- rack (2.2.5)
137
+ rack (2.2.6.3)
128
138
  rack-test (2.0.2)
129
139
  rack (>= 1.3)
130
- rails (7.0.4)
131
- actioncable (= 7.0.4)
132
- actionmailbox (= 7.0.4)
133
- actionmailer (= 7.0.4)
134
- actionpack (= 7.0.4)
135
- actiontext (= 7.0.4)
136
- actionview (= 7.0.4)
137
- activejob (= 7.0.4)
138
- activemodel (= 7.0.4)
139
- activerecord (= 7.0.4)
140
- activestorage (= 7.0.4)
141
- activesupport (= 7.0.4)
140
+ rails (7.0.4.2)
141
+ actioncable (= 7.0.4.2)
142
+ actionmailbox (= 7.0.4.2)
143
+ actionmailer (= 7.0.4.2)
144
+ actionpack (= 7.0.4.2)
145
+ actiontext (= 7.0.4.2)
146
+ actionview (= 7.0.4.2)
147
+ activejob (= 7.0.4.2)
148
+ activemodel (= 7.0.4.2)
149
+ activerecord (= 7.0.4.2)
150
+ activestorage (= 7.0.4.2)
151
+ activesupport (= 7.0.4.2)
142
152
  bundler (>= 1.15.0)
143
- railties (= 7.0.4)
153
+ railties (= 7.0.4.2)
144
154
  rails-dom-testing (2.0.3)
145
155
  activesupport (>= 4.2.0)
146
156
  nokogiri (>= 1.6)
147
- rails-html-sanitizer (1.4.4)
157
+ rails-html-sanitizer (1.5.0)
148
158
  loofah (~> 2.19, >= 2.19.1)
149
- railties (7.0.4)
150
- actionpack (= 7.0.4)
151
- activesupport (= 7.0.4)
159
+ railties (7.0.4.2)
160
+ actionpack (= 7.0.4.2)
161
+ activesupport (= 7.0.4.2)
152
162
  method_source
153
163
  rake (>= 12.2)
154
164
  thor (~> 1.0)
155
165
  zeitwerk (~> 2.5)
156
166
  rainbow (3.1.1)
157
167
  rake (13.0.6)
158
- regexp_parser (2.6.1)
168
+ regexp_parser (2.7.0)
159
169
  rexml (3.2.5)
160
- rubocop (1.43.0)
170
+ rubocop (1.48.0)
161
171
  json (~> 2.3)
162
172
  parallel (~> 1.10)
163
173
  parser (>= 3.2.0.0)
164
174
  rainbow (>= 2.2.2, < 4.0)
165
175
  regexp_parser (>= 1.8, < 3.0)
166
176
  rexml (>= 3.2.5, < 4.0)
167
- rubocop-ast (>= 1.24.1, < 2.0)
177
+ rubocop-ast (>= 1.26.0, < 2.0)
168
178
  ruby-progressbar (~> 1.7)
169
179
  unicode-display_width (>= 2.4.0, < 3.0)
170
- rubocop-ast (1.24.1)
171
- parser (>= 3.1.1.0)
172
- ruby-progressbar (1.11.0)
173
- sus (0.16.0)
180
+ rubocop-ast (1.27.0)
181
+ parser (>= 3.2.1.0)
182
+ ruby-progressbar (1.13.0)
183
+ sus (0.20.3)
174
184
  thor (1.2.1)
175
- timeout (0.3.1)
176
- tzinfo (2.0.5)
185
+ timeout (0.3.2)
186
+ tzinfo (2.0.6)
177
187
  concurrent-ruby (~> 1.0)
178
188
  unicode-display_width (2.4.2)
179
189
  websocket-driver (0.7.5)
180
190
  websocket-extensions (>= 0.1.0)
181
191
  websocket-extensions (0.1.5)
182
- zeitwerk (2.6.6)
192
+ zeitwerk (2.6.7)
183
193
 
184
194
  PLATFORMS
185
195
  arm64-darwin-22
@@ -188,10 +198,11 @@ PLATFORMS
188
198
 
189
199
  DEPENDENCIES
190
200
  combustion
201
+ phlex-testing-nokogiri
191
202
  phlexible!
192
203
  rake (~> 13.0)
193
204
  rubocop (~> 1.21)
194
- sus (~> 0.16.0)
205
+ sus (~> 0.20.0)
195
206
 
196
207
  BUNDLED WITH
197
208
  2.4.1
data/README.md CHANGED
@@ -16,14 +16,81 @@ If bundler is not being used to manage dependencies, install the gem by executin
16
16
 
17
17
  ### Rails
18
18
 
19
- #### `AnchorElement`
19
+ #### `ActionController::ImplicitRender`
20
+
21
+ Adds support for default and `action_missing` rendering of Phlex views. So instead of this:
22
+
23
+ ```ruby
24
+ class UsersController
25
+ def index
26
+ render Views::Users::Index.new
27
+ end
28
+ end
29
+ ```
30
+
31
+ You can do this:
32
+
33
+ ```ruby
34
+ class UsersController
35
+ include Phlexible::Rails::ActionController::ImplicitRender
36
+ end
37
+ ```
38
+
39
+ #### `Responder`
40
+
41
+ If you use [Responders](https://github.com/heartcombo/responders), Phlexible provides a responder to
42
+ support implicit rendering similar to `ActionController::ImplicitRender` above. It will render the
43
+ Phlex view using `respond_with` if one exists, and fall back to default rendering.
44
+
45
+ Just include it in your ApplicationResponder:
46
+
47
+ ```ruby
48
+ class ApplicationResponder < ActionController::Responder
49
+ include Phlexible::Rails::ActionController::ImplicitRender
50
+ include Phlexible::Rails::Responder
51
+ end
52
+ ```
53
+
54
+ Then simply `respond_with` in your action method as normal:
55
+
56
+ ```ruby
57
+ class UsersController < ApplicationController
58
+ def new
59
+ respond_with User.new
60
+ end
61
+
62
+ def index
63
+ respond_with User.all
64
+ end
65
+ end
66
+ ```
67
+
68
+ As Phlex views expect explicit arguments, you can pass these in the `:view_options` keyword
69
+ argument:
70
+
71
+ ```ruby
72
+ class UsersController < ApplicationController
73
+ def index
74
+ respond_with User.all, view_options: { page: 1 }
75
+ end
76
+ end
77
+
78
+ class Views::Users::Index < Phlex::HTML
79
+ def initialize(users, page:); end
80
+ end
81
+ ```
82
+
83
+ This responder requires the use of `ActionController::ImplicitRender`, so dont't forget to include
84
+ that in your `ApplicationController`.
85
+
86
+ #### `AElement`
20
87
 
21
88
  No need to call Rails `link_to` helper, when you can simply render an anchor tag directly with
22
89
  Phlex. But unfortunately that means you lose some of the magic that `link_to` provides. Especially
23
90
  the automatic resolution of URL's and Rails routes.
24
91
 
25
- The `Phlexible::Rails::AnchorElement` module redefines the `a` tag, and passes through the `href`
26
- attribute to Rails `url_for` helper. So you can do this:
92
+ The `Phlexible::Rails::AElement` module passes through the `href` attribute to Rails `url_for`
93
+ helper. So you can do this:
27
94
 
28
95
  ```ruby
29
96
  Rails.application.routes.draw do
@@ -33,14 +100,48 @@ end
33
100
 
34
101
  ```ruby
35
102
  class MyView < Phlex::HTML
36
- include Phlexible::Rails::AnchorElement
103
+ include Phlexible::Rails::AElement
37
104
 
38
- def template
39
- a(href: :articles) { 'View articles' }
40
- end
105
+ def template
106
+ a(href: :articles) { 'View articles' }
107
+ end
41
108
  end
42
109
  ```
43
110
 
111
+ #### 'ButtonTo`
112
+
113
+ Generates a form containing a single button that submits to the URL created by the set of options.
114
+
115
+ It is similar to Rails `button_to` helper, which accepts the value/content of the button as the
116
+ first argument, and a URL or route helper as the second argument.
117
+
118
+ ```ruby
119
+ Phlexible::Rails::ButtonTo.new 'My Button', :root
120
+ ```
121
+
122
+ Alternatively you can pass a block; the result of which will be used as the value of the button.
123
+
124
+ ```ruby
125
+ Phlexible::Rails::ButtonTo.new(:root) { 'Go Home 👉' }
126
+ ```
127
+
128
+ The url argument accepts the same options as Rails `url_for`.
129
+
130
+ The form submits a POST request by default. You can specify a different HTTP verb via the :method
131
+ option.
132
+
133
+ ```ruby
134
+ Phlexible::Rails::ButtonTo.new 'My Button', :root, method: :patch
135
+ ```
136
+
137
+ ##### Options
138
+
139
+ - `:class` - Specify the HTML class name of the button (not the form).
140
+ - `:form_class` - Specify the HTML class name of the form (default: 'button_to').
141
+ - `:data` - This option can be used to add custom data attributes.
142
+ - `:method` - Symbol of the HTTP verb. Supported verbs are :post (default), :get, :delete, :patch,
143
+ and :put.
144
+
44
145
  ### `AliasView`
45
146
 
46
147
  Create an alias at a given `element`, to the given view class.
@@ -49,11 +150,11 @@ So instead of:
49
150
 
50
151
  ```ruby
51
152
  class MyView < Phlex::HTML
52
- def template
53
- div do
54
- render My::Awesome::Component.new
55
- end
153
+ def template
154
+ div do
155
+ render My::Awesome::Component.new
56
156
  end
157
+ end
57
158
  end
58
159
  ```
59
160
 
@@ -61,18 +162,32 @@ You can instead do:
61
162
 
62
163
  ```ruby
63
164
  class MyView < Phlex::HTML
64
- extend Phlexible::AliasView
165
+ extend Phlexible::AliasView
65
166
 
66
- alias_view :awesome, -> { My::Awesome::Component }
167
+ alias_view :awesome, -> { My::Awesome::Component }
67
168
 
68
- def template
69
- div do
70
- awesome
71
- end
169
+ def template
170
+ div do
171
+ awesome
72
172
  end
173
+ end
73
174
  end
74
175
  ```
75
176
 
177
+ ### PageTitle
178
+
179
+ Helper to assist in defining page titles within Phlex views. Also includes support for nested views,
180
+ where each desendent view class will have its title prepended to the page title. Simply assign the
181
+ title to the `page_title` class variable:
182
+
183
+ ```ruby
184
+ class MyView
185
+ self.page_title = 'My Title'
186
+ end
187
+ ```
188
+
189
+ Then call the `page_title` method in the `<head>` of your page.
190
+
76
191
  ## Development
77
192
 
78
193
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Views::Articles::Link < Phlex::HTML
4
- include Phlexible::Rails::AnchorElement
4
+ include Phlexible::Rails::AElement
5
5
 
6
6
  def template
7
- a(href: :root) { 'A link to root' }
7
+ a(href: :root, class: :foo) { 'A link to root' }
8
8
  end
9
9
  end
@@ -30,8 +30,9 @@ module Phlexible
30
30
  #
31
31
  module AliasView
32
32
  def alias_view(element, view_class)
33
- define_method element do |*args, **kwargs, &block|
34
- render view_class.call.new(*args, **kwargs, &block)
33
+ define_method element do |*args, **kwargs, &blk|
34
+ render view_class.call.new(*args, **kwargs), &blk
35
+ # view_class.call.new(*args, **kwargs).call(@_target, view_context: @_view_context, parent: self, &blk)
35
36
  end
36
37
  end
37
38
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexible
4
+ #
5
+ # Helper to assist in defining page titles within Phlex views. Also includes support for nested
6
+ # views, where each desendent view class will have its title prepended to the page title. Simply
7
+ # include the module and assign the title to the `page_title` class variable:
8
+ #
9
+ # class MyView
10
+ # include Phlexible::PageTitle
11
+ # self.page_title = 'My Title'
12
+ # end
13
+ #
14
+ # Then call the `page_title` method in the <head> of your page.
15
+ #
16
+ module PageTitle
17
+ def self.included(base)
18
+ base.class_eval do
19
+ self.class.attr_accessor :page_title
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def page_title
26
+ title = []
27
+
28
+ klass = self.class
29
+ while klass.respond_to?(:page_title)
30
+ title << if klass.page_title.is_a?(Proc)
31
+ instance_exec(&klass.page_title)
32
+ else
33
+ klass.page_title
34
+ end
35
+
36
+ klass = klass.superclass
37
+ end
38
+
39
+ title.compact.join(' - ')
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexible
4
+ module Rails
5
+ # Calls `url_for` for the `href` attribute.
6
+ module AElement
7
+ def a(href:, **kwargs, &block)
8
+ super(href: helpers.url_for(href), **kwargs, &block)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Adds support for default and action_missing rendering of Phlex views. So instead of this:
4
+ #
5
+ # class UsersController
6
+ # def index
7
+ # render Views::Users::Index.new
8
+ # end
9
+ # end
10
+ #
11
+ # You can do this:
12
+ #
13
+ # class UsersController
14
+ # end
15
+ #
16
+ module Phlexible
17
+ module Rails
18
+ module ActionController
19
+ module ImplicitRender
20
+ NUFFIN = 'NUFFIN'
21
+
22
+ def default_render
23
+ render_view_class || super
24
+ end
25
+
26
+ # Renders the Phlex view.
27
+ def render_view_class(view_options = NUFFIN, render_options = {})
28
+ klass = render_options&.key?(:action) ? phlex_view(render_options[:action]) : phlex_view
29
+ return unless klass
30
+
31
+ if view_options == NUFFIN
32
+ view_options = render_options.delete(:view_options) { {} }
33
+ render klass.new(**view_options), render_options
34
+ else
35
+ kwargs = {}
36
+ kwargs = render_options.delete(:view_options) if render_options.key?(:view_options)
37
+
38
+ render klass.new(view_options, **kwargs), render_options
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def method_for_action(action_name)
45
+ if action_method?(action_name)
46
+ action_name
47
+ elsif phlex_view
48
+ '_handle_view_class'
49
+ elsif respond_to?(:action_missing, true)
50
+ '_handle_action_missing'
51
+ end
52
+ end
53
+
54
+ def _handle_view_class(*_args)
55
+ render_view_class
56
+ end
57
+
58
+ def phlex_view(action_name = @_action_name)
59
+ "views/#{controller_path}/#{action_name}".classify.safe_constantize
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generates a form containing a single button that submits to the URL created by the set of options.
4
+ # Similar to Rails `button_to` helper.
5
+ #
6
+ # The form submits a POST request by default. You can specify a different HTTP verb via the :method
7
+ # option.
8
+ module Phlexible
9
+ module Rails
10
+ module ButtonToConcerns
11
+ BUTTON_TAG_METHOD_VERBS = %w[patch put delete].freeze
12
+ DEFAULT_OPTIONS = { method: 'post', form_class: 'button_to' }.freeze
13
+
14
+ def initialize(name = nil, url = nil, options = nil)
15
+ @name = name
16
+ @url = url
17
+ @options = options
18
+ end
19
+
20
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
21
+ def template(&block)
22
+ if block_given?
23
+ @options = @url
24
+ @url = @name
25
+ @name = nil
26
+ end
27
+
28
+ action = helpers.url_for(@url)
29
+ @options = DEFAULT_OPTIONS.merge((@options || {}).symbolize_keys)
30
+
31
+ method = (@options.delete(:method).presence || method_for_options(@options)).to_s
32
+ form_method = method == 'get' ? 'get' : 'post'
33
+
34
+ form action: action, class: @options.delete(:form_class), method: form_method do
35
+ method_tag method
36
+ form_method == 'post' && token_input(action, method.empty? ? 'post' : method)
37
+
38
+ block_given? ? button(**button_attrs, &block) : button(**button_attrs) { @name }
39
+ end
40
+ end
41
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
42
+
43
+ private
44
+
45
+ def button_attrs
46
+ {
47
+ type: 'submit',
48
+ **@options
49
+ }
50
+ end
51
+
52
+ def method_for_options(options)
53
+ if options.is_a?(Array)
54
+ method_for_options(options.last)
55
+ elsif options.respond_to?(:persisted?)
56
+ options.persisted? ? :patch : :post
57
+ elsif options.respond_to?(:to_model)
58
+ method_for_options(options.to_model)
59
+ end
60
+ end
61
+
62
+ def token_input(action, method)
63
+ return unless helpers.protect_against_forgery?
64
+
65
+ name = helpers.request_forgery_protection_token.to_s
66
+ value = helpers.form_authenticity_token(form_options: { action: action, method: method })
67
+
68
+ input type: 'hidden', name: name, value: value, autocomplete: 'off'
69
+ end
70
+
71
+ def method_tag(method)
72
+ return unless BUTTON_TAG_METHOD_VERBS.include?(method)
73
+
74
+ input type: 'hidden', name: '_method', value: method.to_s, autocomplete: 'off'
75
+ end
76
+ end
77
+
78
+ class ButtonTo < Phlex::HTML
79
+ include ButtonToConcerns
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexible
4
+ module Rails
5
+ module Responder
6
+ # Overridden to support implicit rendering of phlex views.
7
+ def default_render
8
+ if @default_response
9
+ @default_response.call(options)
10
+ elsif !get? && has_errors?
11
+ render_phlex_view options.merge(status: :unprocessable_entity)
12
+ else
13
+ render_phlex_view options
14
+ end
15
+ end
16
+
17
+ # Render the Phlex view with the current resource. Falls back to default controller rendering
18
+ # if no Phlex view exists. If a `view_options` keyword argument is given, this will be passed
19
+ # as the keyword arguments of the view initializer.
20
+ #
21
+ # @see Phlexible::Rails::ActionController::ImplicitRender#render_view_class
22
+ def render_phlex_view(options)
23
+ controller.render_view_class(@resource, options) || controller.render(options)
24
+ end
25
+ alias render render_phlex_view
26
+ end
27
+ end
28
+ end
@@ -4,6 +4,14 @@ require 'phlex-rails'
4
4
 
5
5
  module Phlexible
6
6
  module Rails
7
- autoload :AnchorElement, 'phlexible/rails/anchor_element'
7
+ autoload :Responder, 'phlexible/rails/responder'
8
+ autoload :AElement, 'phlexible/rails/a_element'
9
+
10
+ autoload :ButtonTo, 'phlexible/rails/button_to'
11
+ autoload :ButtonToConcerns, 'phlexible/rails/button_to'
12
+
13
+ module ActionController
14
+ autoload :ImplicitRender, 'phlexible/rails/action_controller/implicit_render'
15
+ end
8
16
  end
9
17
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phlexible
4
- VERSION = '0.1.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/phlexible.rb CHANGED
@@ -5,5 +5,6 @@ require 'phlex'
5
5
 
6
6
  module Phlexible
7
7
  autoload :AliasView, 'phlexible/alias_view'
8
+ autoload :PageTitle, 'phlexible/page_title'
8
9
  autoload :Rails, 'phlexible/rails'
9
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phlexible
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Moss
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-10 00:00:00.000000000 Z
11
+ date: 2023-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -16,30 +16,30 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: 1.5.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: 1.5.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: phlex-rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.4'
33
+ version: 0.8.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.4'
41
- description: A bunch of helpers and goodies intended to make life with [Phlex](https://phlex.fun)
42
- even easier!
40
+ version: 0.8.0
41
+ description: A bunch of helpers and goodies intended to make life with Phlex even
42
+ easier!
43
43
  email:
44
44
  - joel@developwithstyle.com
45
45
  executables: []
@@ -67,8 +67,12 @@ files:
67
67
  - fixtures/rails_helper.rb
68
68
  - lib/phlexible.rb
69
69
  - lib/phlexible/alias_view.rb
70
+ - lib/phlexible/page_title.rb
70
71
  - lib/phlexible/rails.rb
71
- - lib/phlexible/rails/anchor_element.rb
72
+ - lib/phlexible/rails/a_element.rb
73
+ - lib/phlexible/rails/action_controller/implicit_render.rb
74
+ - lib/phlexible/rails/button_to.rb
75
+ - lib/phlexible/rails/responder.rb
72
76
  - lib/phlexible/version.rb
73
77
  homepage: https://github.com/joelmoss/phlexible
74
78
  licenses:
@@ -86,16 +90,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
90
  requirements:
87
91
  - - ">="
88
92
  - !ruby/object:Gem::Version
89
- version: 2.7.0
93
+ version: 3.0.0
90
94
  required_rubygems_version: !ruby/object:Gem::Requirement
91
95
  requirements:
92
96
  - - ">="
93
97
  - !ruby/object:Gem::Version
94
98
  version: '0'
95
99
  requirements: []
96
- rubygems_version: 3.4.1
100
+ rubygems_version: 3.4.6
97
101
  signing_key:
98
102
  specification_version: 4
99
- summary: A bunch of helpers and goodies intended to make life with [Phlex](https://phlex.fun)
100
- even easier!
103
+ summary: A bunch of helpers and goodies intended to make life with Phlex even easier!
101
104
  test_files: []
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phlexible
4
- module Rails
5
- module AnchorElement
6
- # @override Calls `url_for` for the :href attribute.
7
- def a(**attributes, &block)
8
- attributes[:href] = helpers.url_for(attributes[:href]) if attributes.key?(:href)
9
-
10
- super(**attributes, &block)
11
- end
12
- end
13
- end
14
- end