futurism 0.4.0 → 0.5.4

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: ba66b2cb1a12fb863e2e0fc34798411d7f95947a197496150e1a499582fc4e28
4
- data.tar.gz: 3f7f290ef2b0b79f9c9e5100e7eaed2520dcb8e481e391bd537649d0023d379b
3
+ metadata.gz: 4e79c03c8d157585784ab3e4f48d2660100acad4e317aa378cdfa94a0c5a3fb9
4
+ data.tar.gz: 5036367ba790b660ef6230e6155192cfedd65973fa65e00fd7b53f071f8a6ae8
5
5
  SHA512:
6
- metadata.gz: e772253cf0ed802d14c6836c0fb7285f7011f79f516fa88cc85e13191b7de0f29ebbc0edbd5c7996f4f858ec4efe4890613605587a2cbd6c17c4ecbad05b4985
7
- data.tar.gz: cf4db9dd38a545a7fe43381dc22597a4c5e77a4023698b19017740fa996e6aa0433e1927c115a1187bb9028ad26e2b36aa3ecd9f66fb19000380a6b6467efffb
6
+ metadata.gz: cf2acd22c20fd40897b6caed2ad897eec3cc98f7ea1fbd9ab31ea19cf276cfa2f94f04ef87a16fe8c68ec03dab1e4e5832a1f4026fe269c58b8114dd1aecb54a
7
+ data.tar.gz: bda0591fb9174ebd6499839be5bfdb8512d8c7c110b9af837f6d8425eb6e9180384234fd493df1945fe51c021c2a0ab0e8ee5537238babd00617ca9bf4a16d8b
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Futurism
2
2
  [![Twitter follow](https://img.shields.io/twitter/follow/julian_rubisch?style=social)](https://twitter.com/julian_rubisch)
3
3
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
4
- [![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors-)
4
+ [![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
5
5
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
6
6
  Lazy-load Rails partials via CableReady
7
7
 
@@ -10,6 +10,27 @@ Lazy-load Rails partials via CableReady
10
10
  <img src="https://user-images.githubusercontent.com/4352208/88374198-9e6f3500-cd99-11ea-804b-0216ed320eff.jpg" alt="birmingham-museums-trust-GrvC6MI-z4w-unsplash" width="50%" align="center"/>
11
11
  <span>Photo by <a href="https://unsplash.com/@birminghammuseumstrust?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Birmingham Museums Trust</a> on <a href="https://unsplash.com/s/photos/futurism?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>
12
12
 
13
+ ## Table of Contents
14
+
15
+ - [Table of Contents](#table-of-contents)
16
+ - [Facts](#facts)
17
+ - [Browser Support](#browser-support)
18
+ - [Usage](#usage)
19
+ - [API](#api)
20
+ - [Resource](#resource)
21
+ - [Explicit Partial](#explicit-partial)
22
+ - [HTML Options](#html-options)
23
+ - [Eager Loading](#eager-loading)
24
+ - [Events](#events)
25
+ - [Installation](#installation)
26
+ - [Manual Installation](#manual-installation)
27
+ - [Authentication](#authentication)
28
+ - [Testing](#testing)
29
+ - [Gotchas](#gotchas)
30
+ - [Contributing](#contributing)
31
+ - [License](#license)
32
+ - [Contributors](#contributors)
33
+
13
34
  ## Facts
14
35
  - only one dependency: CableReady
15
36
  - bundle size (without CableReady) is around [~1.04kB](https://bundlephobia.com/result?p=@minthesize/futurism@0.1.3)
@@ -121,6 +142,19 @@ This will output the following:
121
142
  </tr>
122
143
  ```
123
144
 
145
+ ### Eager Loading
146
+ It may sound surprising to support eager loading in a lazy loading library :joy:, but there's a quite simple use case:
147
+
148
+ Suppose you have some hidden interactive portion of your page, like a tab or dropdown. You don't want its content to block the initial page load, but once that is done, you occasionally don't want to wait for the element to become visible and trigger the `IntersectionObserver`, you want to lazy load its contents right after it's added to the DOM.
149
+
150
+ Futurism makes that dead simple:
151
+
152
+ ```erb
153
+ <%= futurize 'some_tab', eager: true, extends: :tr do %>
154
+ <div class="placeholder"</td>
155
+ <% end %>
156
+ ```
157
+
124
158
  ## Events
125
159
 
126
160
  Once your futurize element has been rendered, the `futurize:appeared` custom event will be called.
@@ -155,7 +189,7 @@ $ bin/yarn add @minthesize/futurism
155
189
  In your `app/javascript/channels/index.js`, add the following
156
190
 
157
191
  ```js
158
- import * as Futurism from '@minthesize/futurism''
192
+ import * as Futurism from '@minthesize/futurism'
159
193
 
160
194
  import consumer from './consumer'
161
195
 
@@ -163,6 +197,48 @@ Futurism.initializeElements()
163
197
  Futurism.createSubscription(consumer)
164
198
  ```
165
199
 
200
+ ## Authentication
201
+ For authentication, you can rely on ActionCable identifiers, for example, if you use Devise:
202
+
203
+ ```ruby
204
+ module ApplicationCable
205
+ class Connection < ActionCable::Connection::Base
206
+ identified_by :current_user
207
+
208
+ def connect
209
+ self.current_user = env["warden"].user || reject_unauthorized_connection
210
+ end
211
+ end
212
+ end
213
+ ```
214
+
215
+ The [Stimulus Reflex Docs](https://docs.stimulusreflex.com/authentication) have an excellent section about all sorts of authentication.
216
+
217
+ ## Testing
218
+ In Rails system tests there is a chance that flaky errors will occur due to Capybara not waiting for the placeholder elements to be replaced. To overcome this, add the flag
219
+
220
+ ```ruby
221
+ Futurism.skip_in_test = true
222
+ ```
223
+
224
+ to an initializer, for example `config/initializers/futurism.rb`.
225
+
226
+ ## Gotchas
227
+
228
+ ### ActiveStorage URLs aren't correct in development
229
+
230
+ Out of the box, Rails will prefix generated urls with `http://example.org` rather than `http://localhost`, much like ActionMailer. To amend this, add
231
+
232
+ ```ruby
233
+ # config/environments/development.rb
234
+ config.action_controller.default_url_options = {host: "localhost", port: 3000}
235
+
236
+ # config/environments/production.rb
237
+ config.action_controller.default_url_options = {host: "mysite.com"}
238
+ ```
239
+
240
+ to your environments.
241
+
166
242
  ## Contributing
167
243
 
168
244
  ## License
@@ -189,6 +265,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
189
265
  <td align="center"><a href="http://fractaledmind.com"><img src="https://avatars3.githubusercontent.com/u/5077225?v=4" width="100px;" alt=""/><br /><sub><b>Stephen Margheim</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/commits?author=fractaledmind" title="Code">💻</a></td>
190
266
  <td align="center"><a href="http://hass.codes"><img src="https://avatars2.githubusercontent.com/u/1064205?v=4" width="100px;" alt=""/><br /><sub><b>Hassanin Ahmed</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/commits?author=sas1ni69" title="Code">💻</a></td>
191
267
  <td align="center"><a href="https://marcoroth.dev"><img src="https://avatars2.githubusercontent.com/u/6411752?v=4" width="100px;" alt=""/><br /><sub><b>Marco Roth</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/commits?author=marcoroth" title="Code">💻</a></td>
268
+ <td align="center"><a href="https://viedit.com"><img src="https://avatars1.githubusercontent.com/u/49990587?v=4" width="100px;" alt=""/><br /><sub><b>Viedit com</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/commits?author=vieditcom" title="Documentation">📖</a></td>
269
+ <td align="center"><a href="http://scottbarrow.ca"><img src="https://avatars2.githubusercontent.com/u/5571736?v=4" width="100px;" alt=""/><br /><sub><b>Scott Barrow</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/commits?author=scottbarrow" title="Code">💻</a></td>
270
+ <td align="center"><a href="http://domchristie.co.uk"><img src="https://avatars0.githubusercontent.com/u/111734?v=4" width="100px;" alt=""/><br /><sub><b>Dom Christie</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/pulls?q=is%3Apr+reviewed-by%3Adomchristie" title="Reviewed Pull Requests">👀</a></td>
271
+ <td align="center"><a href="http://www.rickychilcott.com"><img src="https://avatars1.githubusercontent.com/u/445759?v=4" width="100px;" alt=""/><br /><sub><b>Ricky Chilcott</b></sub></a><br /><a href="https://github.com/julianrubisch/futurism/pulls?q=is%3Apr+reviewed-by%3Arickychilcott" title="Reviewed Pull Requests">👀</a></td>
192
272
  </tr>
193
273
  </table>
194
274
 
@@ -10,6 +10,8 @@ module Futurism
10
10
 
11
11
  autoload :Helpers, "futurism/helpers"
12
12
 
13
+ mattr_accessor :skip_in_test
14
+
13
15
  ActiveSupport.on_load(:action_view) {
14
16
  include Futurism::Helpers
15
17
  }
@@ -1,5 +1,16 @@
1
+ require "rails"
2
+ require "action_cable"
3
+ require "cable_ready"
1
4
  require "futurism/engine"
5
+ require "futurism/channel"
6
+ require "futurism/helpers"
2
7
 
3
8
  module Futurism
4
- # Your code goes here...
9
+ extend ActiveSupport::Autoload
10
+
11
+ autoload :Helpers, "futurism/helpers"
12
+
13
+ ActiveSupport.on_load(:action_view) {
14
+ include Futurism::Helpers
15
+ }
5
16
  end
@@ -2,8 +2,16 @@ module Futurism
2
2
  class Channel < ActionCable::Channel::Base
3
3
  include CableReady::Broadcaster
4
4
 
5
+ def stream_name
6
+ ids = connection.identifiers.map { |identifier| send(identifier).try(:id) || send(identifier) }
7
+ [
8
+ params[:channel],
9
+ ids.select(&:present?).join(";")
10
+ ].select(&:present?).join(":")
11
+ end
12
+
5
13
  def subscribed
6
- stream_from "Futurism::Channel"
14
+ stream_from stream_name
7
15
  end
8
16
 
9
17
  def receive(data)
@@ -15,7 +23,7 @@ module Futurism
15
23
  resources.each do |signed_params, sgid|
16
24
  selector = "[data-signed-params='#{signed_params}']"
17
25
  selector << "[data-sgid='#{sgid}']" if sgid.present?
18
- cable_ready["Futurism::Channel"].outer_html(
26
+ cable_ready[stream_name].outer_html(
19
27
  selector: selector,
20
28
  html: ApplicationController.render(resource(signed_params: signed_params, sgid: sgid))
21
29
  )
@@ -29,7 +37,11 @@ module Futurism
29
37
  def resource(signed_params:, sgid:)
30
38
  return GlobalID::Locator.locate_signed(sgid) if sgid.present?
31
39
 
32
- Rails.application.message_verifier("futurism").verify(signed_params)
40
+ Rails
41
+ .application
42
+ .message_verifier("futurism")
43
+ .verify(signed_params)
44
+ .deep_transform_values { |value| value.is_a?(String) && value.start_with?("gid://") ? GlobalID::Locator.locate(value) : value }
33
45
  end
34
46
  end
35
47
  end
@@ -2,8 +2,16 @@ module Futurism
2
2
  class Channel < ActionCable::Channel::Base
3
3
  include CableReady::Broadcaster
4
4
 
5
+ def stream_name
6
+ ids = connection.identifiers.map { |identifier| send(identifier).try(:id) || send(identifier) }
7
+ [
8
+ params[:channel],
9
+ ids.select(&:present?).join(";")
10
+ ].select(&:present?).join(":")
11
+ end
12
+
5
13
  def subscribed
6
- stream_from "Futurism::Channel"
14
+ stream_from stream_name
7
15
  end
8
16
 
9
17
  def receive(data)
@@ -15,7 +23,7 @@ module Futurism
15
23
  resources.each do |signed_params, sgid|
16
24
  selector = "[data-signed-params='#{signed_params}']"
17
25
  selector << "[data-sgid='#{sgid}']" if sgid.present?
18
- cable_ready["Futurism::Channel"].outer_html(
26
+ cable_ready[stream_name].outer_html(
19
27
  selector: selector,
20
28
  html: ApplicationController.render(resource(signed_params: signed_params, sgid: sgid))
21
29
  )
@@ -29,7 +37,11 @@ module Futurism
29
37
  def resource(signed_params:, sgid:)
30
38
  return GlobalID::Locator.locate_signed(sgid) if sgid.present?
31
39
 
32
- Rails.application.message_verifier("futurism").verify(signed_params)
40
+ Rails
41
+ .application
42
+ .message_verifier("futurism")
43
+ .verify(signed_params)
44
+ .deep_transform_values { |value| value.is_a?(String) && value.start_with?("gid://") ? GlobalID::Locator.locate(value) : value }
33
45
  end
34
46
  end
35
47
  end
@@ -1,6 +1,14 @@
1
1
  module Futurism
2
2
  module Helpers
3
3
  def futurize(records_or_string = nil, extends:, **options, &block)
4
+ if Rails.env.test? && Futurism.skip_in_test
5
+ if records_or_string.nil?
6
+ return render **options
7
+ else
8
+ return render records_or_string, **options
9
+ end
10
+ end
11
+
4
12
  placeholder = capture(&block)
5
13
 
6
14
  if records_or_string.is_a?(ActiveRecord::Base) || records_or_string.is_a?(ActiveRecord::Relation)
@@ -36,38 +44,49 @@ module Futurism
36
44
  class Element
37
45
  include ActionView::Helpers
38
46
 
39
- attr_reader :extends, :placeholder, :html_options, :model, :options
47
+ attr_reader :extends, :placeholder, :html_options, :data_attributes, :model, :options, :eager
40
48
 
41
49
  def initialize(extends:, placeholder:, options:)
42
50
  @extends = extends
43
51
  @placeholder = placeholder
52
+ @eager = options.delete(:eager)
44
53
  @html_options = options.delete(:html_options) || {}
54
+ @data_attributes = html_options.fetch(:data, {}).except(:sgid, :signed_params)
45
55
  @model = options.delete(:model)
46
- @options = options
56
+ @options = data_attributes.any? ? options.merge(data: data_attributes) : options
47
57
  end
48
58
 
49
59
  def dataset
50
- {
60
+ data_attributes.merge({
51
61
  signed_params: signed_params,
52
- sgid: model && model.to_sgid.to_s
53
- }
62
+ sgid: model && model.to_sgid.to_s,
63
+ eager: eager.presence
64
+ })
54
65
  end
55
66
 
56
67
  def render
57
68
  case extends
58
69
  when :li
59
- content_tag :li, placeholder, {data: dataset, is: "futurism-li"}.merge(html_options)
70
+ content_tag :li, placeholder, html_options.deep_merge({data: dataset, is: "futurism-li"})
60
71
  when :tr
61
- content_tag :tr, placeholder, {data: dataset, is: "futurism-table-row"}.merge(html_options)
72
+ content_tag :tr, placeholder, html_options.deep_merge({data: dataset, is: "futurism-table-row"})
62
73
  else
63
- content_tag :"futurism-element", placeholder, {data: dataset}.merge(html_options)
74
+ content_tag :"futurism-element", placeholder, html_options.deep_merge({data: dataset})
75
+ end
76
+ end
77
+
78
+ def transformed_options
79
+ require_relative "shims/deep_transform_values" unless options.respond_to? :deep_transform_values
80
+
81
+ options.deep_transform_values do |value|
82
+ value.is_a?(ActiveRecord::Base) && !value.new_record? ? value.to_global_id.to_s : value
64
83
  end
65
84
  end
66
85
 
67
86
  private
68
87
 
69
88
  def signed_params
70
- Rails.application.message_verifier("futurism").generate(options)
89
+ Rails.application.message_verifier("futurism").generate(transformed_options)
71
90
  end
72
91
  end
73
92
  end
@@ -1,12 +1,22 @@
1
1
  module Futurism
2
2
  module Helpers
3
3
  def futurize(records_or_string = nil, extends:, **options, &block)
4
+ if Rails.env.test? && Futurism.skip_in_test
5
+ if records_or_string.nil?
6
+ render options
7
+ else
8
+ render records_or_string, options
9
+ end
10
+ return
11
+ end
12
+
4
13
  placeholder = capture(&block)
5
14
 
6
15
  if records_or_string.is_a?(ActiveRecord::Base) || records_or_string.is_a?(ActiveRecord::Relation)
7
16
  futurize_active_record(records_or_string, extends: extends, placeholder: placeholder, **options)
8
17
  elsif records_or_string.is_a?(String)
9
- futurize_with_options(extends: extends, placeholder: placeholder, partial: records_or_string, **options)
18
+ html_options = options.delete(:html_options)
19
+ futurize_with_options(extends: extends, placeholder: placeholder, partial: records_or_string, locals: options, html_options: html_options)
10
20
  else
11
21
  futurize_with_options(extends: extends, placeholder: placeholder, **options)
12
22
  end
@@ -35,38 +45,49 @@ module Futurism
35
45
  class Element
36
46
  include ActionView::Helpers
37
47
 
38
- attr_reader :extends, :placeholder, :html_options, :model, :options
48
+ attr_reader :extends, :placeholder, :html_options, :data_attributes, :model, :options, :eager
39
49
 
40
50
  def initialize(extends:, placeholder:, options:)
41
51
  @extends = extends
42
52
  @placeholder = placeholder
53
+ @eager = options.delete(:eager)
43
54
  @html_options = options.delete(:html_options) || {}
55
+ @data_attributes = html_options.fetch(:data, {}).except(:sgid, :signed_params)
44
56
  @model = options.delete(:model)
45
- @options = options
57
+ @options = data_attributes.any? ? options.merge(data: data_attributes) : options
46
58
  end
47
59
 
48
60
  def dataset
49
- {
61
+ data_attributes.merge({
50
62
  signed_params: signed_params,
51
- sgid: model && model.to_sgid.to_s
52
- }
63
+ sgid: model && model.to_sgid.to_s,
64
+ eager: eager.presence
65
+ })
53
66
  end
54
67
 
55
68
  def render
56
69
  case extends
57
70
  when :li
58
- content_tag :li, placeholder, {data: dataset, is: "futurism-li"}.merge(html_options)
71
+ content_tag :li, placeholder, html_options.deep_merge({data: dataset, is: "futurism-li"})
59
72
  when :tr
60
- content_tag :tr, placeholder, {data: dataset, is: "futurism-table-row"}.merge(html_options)
73
+ content_tag :tr, placeholder, html_options.deep_merge({data: dataset, is: "futurism-table-row"})
61
74
  else
62
- content_tag :"futurism-element", placeholder, {data: dataset}.merge(html_options)
75
+ content_tag :"futurism-element", placeholder, html_options.deep_merge({data: dataset})
76
+ end
77
+ end
78
+
79
+ def transformed_options
80
+ require_relative "shims/deep_transform_values" unless options.respond_to? :deep_transform_values
81
+
82
+ options.deep_transform_values do |value|
83
+ value.is_a?(ActiveRecord::Base) && !value.new_record? ? value.to_global_id.to_s : value
63
84
  end
64
85
  end
65
86
 
66
87
  private
67
88
 
68
89
  def signed_params
69
- Rails.application.message_verifier("futurism").generate(options)
90
+ Rails.application.message_verifier("futurism").generate(transformed_options)
70
91
  end
71
92
  end
72
93
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all values converted by the block operation.
5
+ # This includes the values from the root hash and from all
6
+ # nested hashes and arrays.
7
+ #
8
+ # hash = { person: { name: 'Rob', age: '28' } }
9
+ #
10
+ # hash.deep_transform_values{ |value| value.to_s.upcase }
11
+ # # => {person: {name: "ROB", age: "28"}}
12
+ def deep_transform_values(&block)
13
+ _deep_transform_values_in_object(self, &block)
14
+ end
15
+
16
+ # Destructively converts all values by using the block operation.
17
+ # This includes the values from the root hash and from all
18
+ # nested hashes and arrays.
19
+ def deep_transform_values!(&block)
20
+ _deep_transform_values_in_object!(self, &block)
21
+ end
22
+
23
+ private
24
+
25
+ # Support methods for deep transforming nested hashes and arrays.
26
+ def _deep_transform_values_in_object(object, &block)
27
+ case object
28
+ when Hash
29
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
30
+ when Array
31
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
32
+ else
33
+ yield(object)
34
+ end
35
+ end
36
+
37
+ def _deep_transform_values_in_object!(object, &block)
38
+ case object
39
+ when Hash
40
+ object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
41
+ when Array
42
+ object.map! { |e| _deep_transform_values_in_object!(e, &block) }
43
+ else
44
+ yield(object)
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Futurism
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.4"
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: futurism
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Rubisch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-24 00:00:00.000000000 Z
11
+ date: 2020-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: appraisal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +142,14 @@ dependencies:
128
142
  requirements:
129
143
  - - ">="
130
144
  - !ruby/object:Gem::Version
131
- version: '6'
145
+ version: '5.2'
132
146
  type: :runtime
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - ">="
137
151
  - !ruby/object:Gem::Version
138
- version: '6'
152
+ version: '5.2'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: cable_ready
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -170,6 +184,7 @@ files:
170
184
  - lib/futurism/engine.rb
171
185
  - lib/futurism/helpers.rb
172
186
  - lib/futurism/helpers.rb~
187
+ - lib/futurism/shims/deep_transform_values.rb
173
188
  - lib/futurism/version.rb
174
189
  - lib/tasks/futurism_tasks.rake
175
190
  - lib/tasks/futurism_tasks.rake~