phlexible 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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