futurism 0.8.0 → 1.0.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 +4 -4
- data/README.md +42 -20
- data/lib/futurism/#helpers.rb# +105 -0
- data/lib/futurism/channel.rb +4 -2
- data/lib/futurism/channel.rb~ +2 -28
- data/lib/futurism/helpers.rb +21 -8
- data/lib/futurism/helpers.rb~ +20 -9
- data/lib/futurism/resolver/controller/renderer.rb +20 -1
- data/lib/futurism/resolver/resources.rb +38 -5
- data/lib/futurism/resolver/resources.rb~ +58 -34
- data/lib/futurism/version.rb +1 -1
- data/lib/futurism/version.rb~ +1 -1
- data/lib/futurism.rb +5 -2
- data/lib/tasks/futurism_tasks.rake +2 -2
- data/lib/tasks/futurism_tasks.rake~ +39 -4
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 414f6857d0112042c7745a9198e9e9c05d2886d3649f955d53d4ed09fed1dddc
|
4
|
+
data.tar.gz: cd55e6f01214c0379e2a5b2d0505c76486cc388114daa3888439e608a0a74335
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14de66605b2c41ef1cc6aca2c42507a856dfd67cbb1dc23de029b77bfb5c24b5b6a5a2ecf65b95cef5622c45dfef6ecccd05059daeaf25615a12356015b5b614
|
7
|
+
data.tar.gz: a63476d5c42a5db0ae0220f71b4c5a4792aaf529c0741df322a239c8be458b8433c94bd461574833c1b102e1b8f444038adb1c7f66a3a16d6b73025672fa8022
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
6
6
|
Lazy-load Rails partials via CableReady
|
7
7
|
|
8
|
-
:rotating_light: *
|
8
|
+
:rotating_light: *BREAKING CHANGE: With v1.0, futurism has been transferred to the [stimulusreflex](https://github.com/stimulusreflex) organization. Please update your npm package to `@stimulus_reflex/futurism` accordingly* :rotating_light:
|
9
9
|
|
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&utm_medium=referral&utm_content=creditCopyText">Birmingham Museums Trust</a> on <a href="https://unsplash.com/s/photos/futurism?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></span>
|
@@ -21,6 +21,7 @@ Lazy-load Rails partials via CableReady
|
|
21
21
|
- [Explicit Partial](#explicit-partial)
|
22
22
|
- [HTML Options](#html-options)
|
23
23
|
- [Eager Loading](#eager-loading)
|
24
|
+
- [Broadcast Partials Individually](#broadcast-partials-individually)
|
24
25
|
- [Events](#events)
|
25
26
|
- [Installation](#installation)
|
26
27
|
- [Manual Installation](#manual-installation)
|
@@ -33,7 +34,7 @@ Lazy-load Rails partials via CableReady
|
|
33
34
|
|
34
35
|
## Facts
|
35
36
|
- only one dependency: CableReady
|
36
|
-
- bundle size (without CableReady) is around [~2.46kB](https://bundlephobia.com/result?p=@
|
37
|
+
- bundle size (without CableReady) is around [~2.46kB](https://bundlephobia.com/result?p=@stimulus_reflex/futurism@0.7.2)
|
37
38
|
|
38
39
|
### Browser Support
|
39
40
|
|
@@ -68,6 +69,8 @@ You can pass the placeholder as a block:
|
|
68
69
|
|
69
70
|

|
70
71
|
|
72
|
+
You can also omit the placeholder, which falls back to [eager loading](#eager-loading).
|
73
|
+
|
71
74
|
## API
|
72
75
|
|
73
76
|
Currently there are two ways to call `futurize`, designed to wrap `render`'s behavior:
|
@@ -171,6 +174,19 @@ Futurism makes that dead simple:
|
|
171
174
|
<% end %>
|
172
175
|
```
|
173
176
|
|
177
|
+
### Broadcast Partials Individually
|
178
|
+
Futurism's default behavior is to `broadcast` partials as they are generated in batches:
|
179
|
+
|
180
|
+
On the client side, `IntersectionObserver` events are triggered in a debounced fashion, so several `render`s are performed on the server for each of those events. By default, futurism will group those to a single `broadcast` call (to save server CPU time).
|
181
|
+
|
182
|
+
For collections, however, you can opt into individual broadcasts by specifying `broadcast_each: true` in your helper usage:
|
183
|
+
|
184
|
+
```erb
|
185
|
+
<%= futurize @posts, broadcast_each: true, extends: :tr do %>
|
186
|
+
<div class="placeholder"</td>
|
187
|
+
<% end %>
|
188
|
+
```
|
189
|
+
|
174
190
|
## Events
|
175
191
|
|
176
192
|
Once your futurize element has been rendered, the `futurize:appeared` custom event will be called.
|
@@ -193,19 +209,19 @@ To copy over the javascript files to your application, run
|
|
193
209
|
$ bin/rails futurism:install
|
194
210
|
```
|
195
211
|
|
196
|
-
**! Note that the installer will run `yarn add @
|
212
|
+
**! Note that the installer will run `yarn add @stimulus_reflex/futurism` for you !**
|
197
213
|
|
198
214
|
### Manual Installation
|
199
215
|
After `bundle`, install the Javascript library:
|
200
216
|
|
201
217
|
```bash
|
202
|
-
$ bin/yarn add @
|
218
|
+
$ bin/yarn add @stimulus_reflex/futurism
|
203
219
|
```
|
204
220
|
|
205
221
|
In your `app/javascript/channels/index.js`, add the following
|
206
222
|
|
207
223
|
```js
|
208
|
-
import * as Futurism from '@
|
224
|
+
import * as Futurism from '@stimulus_reflex/futurism'
|
209
225
|
|
210
226
|
import consumer from './consumer'
|
211
227
|
|
@@ -273,7 +289,7 @@ git clone https://github.com/leastbad/stimulus_reflex_harness.git
|
|
273
289
|
cd stimulus_reflex_harness
|
274
290
|
git checkout futurism
|
275
291
|
# Edit Gemfile to point point to local gem (e.g. `gem "futurism", path: "../futurism"`)
|
276
|
-
# yarn link @
|
292
|
+
# yarn link @stimulus_reflex/futurism
|
277
293
|
|
278
294
|
|
279
295
|
# Do your work, Submit PR, Profit!
|
@@ -290,6 +306,12 @@ cd path/to/project
|
|
290
306
|
yarn install --force
|
291
307
|
```
|
292
308
|
|
309
|
+
### Release
|
310
|
+
|
311
|
+
1. Update the version numbers in `javascript/package.json` and `lib/futurism/version.rb`
|
312
|
+
2. `rake release`
|
313
|
+
3. `cd javascript && npm publish --access public`
|
314
|
+
|
293
315
|
## License
|
294
316
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
295
317
|
|
@@ -302,25 +324,25 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
302
324
|
<!-- markdownlint-disable -->
|
303
325
|
<table>
|
304
326
|
<tr>
|
305
|
-
<td align="center"><a href="http://www.julianrubisch.at"><img src="https://avatars0.githubusercontent.com/u/4352208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Julian Rubisch</b></sub></a><br /><a href="https://github.com/
|
306
|
-
<td align="center"><a href="https://github.com/darkrubyist"><img src="https://avatars2.githubusercontent.com/u/11207292?v=4?s=100" width="100px;" alt=""/><br /><sub><b>darkrubyist</b></sub></a><br /><a href="https://github.com/
|
307
|
-
<td align="center"><a href="https://ParamagicDev.github.io/portfolio"><img src="https://avatars2.githubusercontent.com/u/26425882?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Konnor Rogers</b></sub></a><br /><a href="https://github.com/
|
327
|
+
<td align="center"><a href="http://www.julianrubisch.at"><img src="https://avatars0.githubusercontent.com/u/4352208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Julian Rubisch</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=julianrubisch" title="Code">💻</a></td>
|
328
|
+
<td align="center"><a href="https://github.com/darkrubyist"><img src="https://avatars2.githubusercontent.com/u/11207292?v=4?s=100" width="100px;" alt=""/><br /><sub><b>darkrubyist</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=darkrubyist" title="Code">💻</a> <a href="https://github.com/stimulusreflex/futurism/commits?author=darkrubyist" title="Documentation">📖</a></td>
|
329
|
+
<td align="center"><a href="https://ParamagicDev.github.io/portfolio"><img src="https://avatars2.githubusercontent.com/u/26425882?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Konnor Rogers</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=ParamagicDev" title="Code">💻</a></td>
|
308
330
|
<td align="center"><a href="https://www.andrewm.codes"><img src="https://avatars1.githubusercontent.com/u/18423853?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Mason</b></sub></a><br /><a href="#maintenance-andrewmcodes" title="Maintenance">🚧</a></td>
|
309
|
-
<td align="center"><a href="http://gorails.com"><img src="https://avatars1.githubusercontent.com/u/67093?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Oliver</b></sub></a><br /><a href="https://github.com/
|
310
|
-
<td align="center"><a href="https://github.com/leastbad"><img src="https://avatars2.githubusercontent.com/u/38150464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>leastbad</b></sub></a><br /><a href="https://github.com/
|
311
|
-
<td align="center"><a href="http://code.digimonkey.com"><img src="https://avatars0.githubusercontent.com/u/74207?v=4?s=100" width="100px;" alt=""/><br /><sub><b>M. E. Patterson</b></sub></a><br /><a href="https://github.com/
|
331
|
+
<td align="center"><a href="http://gorails.com"><img src="https://avatars1.githubusercontent.com/u/67093?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Oliver</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=excid3" title="Code">💻</a> <a href="https://github.com/stimulusreflex/futurism/pulls?q=is%3Apr+reviewed-by%3Aexcid3" title="Reviewed Pull Requests">👀</a></td>
|
332
|
+
<td align="center"><a href="https://github.com/leastbad"><img src="https://avatars2.githubusercontent.com/u/38150464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>leastbad</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=leastbad" title="Code">💻</a> <a href="https://github.com/stimulusreflex/futurism/pulls?q=is%3Apr+reviewed-by%3Aleastbad" title="Reviewed Pull Requests">👀</a></td>
|
333
|
+
<td align="center"><a href="http://code.digimonkey.com"><img src="https://avatars0.githubusercontent.com/u/74207?v=4?s=100" width="100px;" alt=""/><br /><sub><b>M. E. Patterson</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/issues?q=author%3Amepatterson" title="Bug reports">🐛</a></td>
|
312
334
|
</tr>
|
313
335
|
<tr>
|
314
|
-
<td align="center"><a href="http://fractaledmind.com"><img src="https://avatars3.githubusercontent.com/u/5077225?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stephen Margheim</b></sub></a><br /><a href="https://github.com/
|
315
|
-
<td align="center"><a href="http://hass.codes"><img src="https://avatars2.githubusercontent.com/u/1064205?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hassanin Ahmed</b></sub></a><br /><a href="https://github.com/
|
316
|
-
<td align="center"><a href="https://marcoroth.dev"><img src="https://avatars2.githubusercontent.com/u/6411752?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marco Roth</b></sub></a><br /><a href="https://github.com/
|
317
|
-
<td align="center"><a href="https://viedit.com"><img src="https://avatars1.githubusercontent.com/u/49990587?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Viedit com</b></sub></a><br /><a href="https://github.com/
|
318
|
-
<td align="center"><a href="http://scottbarrow.ca"><img src="https://avatars2.githubusercontent.com/u/5571736?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Scott Barrow</b></sub></a><br /><a href="https://github.com/
|
319
|
-
<td align="center"><a href="http://domchristie.co.uk"><img src="https://avatars0.githubusercontent.com/u/111734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dom Christie</b></sub></a><br /><a href="https://github.com/
|
320
|
-
<td align="center"><a href="http://www.rickychilcott.com"><img src="https://avatars1.githubusercontent.com/u/445759?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ricky Chilcott</b></sub></a><br /><a href="https://github.com/
|
336
|
+
<td align="center"><a href="http://fractaledmind.com"><img src="https://avatars3.githubusercontent.com/u/5077225?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stephen Margheim</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=fractaledmind" title="Code">💻</a></td>
|
337
|
+
<td align="center"><a href="http://hass.codes"><img src="https://avatars2.githubusercontent.com/u/1064205?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hassanin Ahmed</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=sas1ni69" title="Code">💻</a></td>
|
338
|
+
<td align="center"><a href="https://marcoroth.dev"><img src="https://avatars2.githubusercontent.com/u/6411752?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marco Roth</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=marcoroth" title="Code">💻</a></td>
|
339
|
+
<td align="center"><a href="https://viedit.com"><img src="https://avatars1.githubusercontent.com/u/49990587?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Viedit com</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=vieditcom" title="Documentation">📖</a></td>
|
340
|
+
<td align="center"><a href="http://scottbarrow.ca"><img src="https://avatars2.githubusercontent.com/u/5571736?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Scott Barrow</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=scottbarrow" title="Code">💻</a></td>
|
341
|
+
<td align="center"><a href="http://domchristie.co.uk"><img src="https://avatars0.githubusercontent.com/u/111734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dom Christie</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/pulls?q=is%3Apr+reviewed-by%3Adomchristie" title="Reviewed Pull Requests">👀</a></td>
|
342
|
+
<td align="center"><a href="http://www.rickychilcott.com"><img src="https://avatars1.githubusercontent.com/u/445759?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ricky Chilcott</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/pulls?q=is%3Apr+reviewed-by%3Arickychilcott" title="Reviewed Pull Requests">👀</a></td>
|
321
343
|
</tr>
|
322
344
|
<tr>
|
323
|
-
<td align="center"><a href="https://github.com/mansakondo"><img src="https://avatars.githubusercontent.com/u/47113995?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mansakondo</b></sub></a><br /><a href="https://github.com/
|
345
|
+
<td align="center"><a href="https://github.com/mansakondo"><img src="https://avatars.githubusercontent.com/u/47113995?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mansakondo</b></sub></a><br /><a href="https://github.com/stimulusreflex/futurism/commits?author=mansakondo" title="Code">💻</a></td>
|
324
346
|
</tr>
|
325
347
|
</table>
|
326
348
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Futurism
|
2
|
+
module Helpers
|
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
|
+
|
12
|
+
placeholder = capture(&block)
|
13
|
+
|
14
|
+
if records_or_string.is_a?(ActiveRecord::Base) || records_or_string.is_a?(ActiveRecord::Relation)
|
15
|
+
futurize_active_record(records_or_string, extends: extends, placeholder: placeholder, **options)
|
16
|
+
elsif records_or_string.is_a?(String)
|
17
|
+
html_options = options.delete(:html_options)
|
18
|
+
futurize_with_options(extends: extends, placeholder: placeholder, partial: records_or_string, locals: options, html_options: html_options)
|
19
|
+
else
|
20
|
+
futurize_with_options(extends: extends, placeholder: placeholder, **options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def futurize_with_options(extends:, placeholder:, **options)
|
25
|
+
collection = options.delete(:collection)
|
26
|
+
if collection.nil?
|
27
|
+
WrappingFuturismElement.new(extends: extends, placeholder: placeholder, options: options).render
|
28
|
+
else
|
29
|
+
collection_class_name = collection.try(:klass).try(:name) || collection.first.class.to_s
|
30
|
+
as = options.delete(:as) || collection_class_name.underscore
|
31
|
+
collection.each_with_index.map { |record, index|
|
32
|
+
WrappingFuturismElement.new(extends: extends, placeholder: placeholder, options: options.deep_merge(locals: {as.to_sym => record, "#{as}_counter".to_sym => index})).render
|
33
|
+
}.join.html_safe
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def futurize_active_record(records, extends:, placeholder:, **options)
|
38
|
+
Array(records).map { |record|
|
39
|
+
WrappingFuturismElement.new(extends: extends, options: options.merge(model: record), placeholder: placeholder).render
|
40
|
+
}.join.html_safe
|
41
|
+
end
|
42
|
+
|
43
|
+
# wraps functionality for rendering a futurism element
|
44
|
+
class WrappingFuturismElement
|
45
|
+
include ActionView::Helpers
|
46
|
+
include Futurism::MessageVerifier
|
47
|
+
|
48
|
+
attr_reader :extends, :placeholder, :html_options, :data_attributes, :model, :options, :eager, :controller
|
49
|
+
|
50
|
+
def initialize(extends:, placeholder:, options:)
|
51
|
+
@extends = extends
|
52
|
+
@placeholder = placeholder
|
53
|
+
@eager = options.delete(:eager)
|
54
|
+
@controller = options.delete(:controller)
|
55
|
+
@html_options = options.delete(:html_options) || {}
|
56
|
+
@data_attributes = html_options.fetch(:data, {}).except(:sgid, :signed_params)
|
57
|
+
@model = options.delete(:model)
|
58
|
+
@options = data_attributes.any? ? options.merge(data: data_attributes) : options
|
59
|
+
end
|
60
|
+
|
61
|
+
def dataset
|
62
|
+
data_attributes.merge({
|
63
|
+
signed_params: signed_params,
|
64
|
+
sgid: model && model.to_sgid.to_s,
|
65
|
+
eager: eager.presence,
|
66
|
+
signed_controller: signed_controller
|
67
|
+
})
|
68
|
+
end
|
69
|
+
|
70
|
+
def render
|
71
|
+
case extends
|
72
|
+
when :li
|
73
|
+
content_tag :li, placeholder, html_options.deep_merge({data: dataset, is: "futurism-li"})
|
74
|
+
when :tr
|
75
|
+
content_tag :tr, placeholder, html_options.deep_merge({data: dataset, is: "futurism-table-row"})
|
76
|
+
else
|
77
|
+
content_tag :"futurism-element", placeholder, html_options.deep_merge({data: dataset})
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def transformed_options
|
82
|
+
require_relative "shims/deep_transform_values" unless options.respond_to? :deep_transform_values
|
83
|
+
|
84
|
+
options.deep_transform_values do |value|
|
85
|
+
next(value) unless value.respond_to?(:to_global_id)
|
86
|
+
next(value) if value.is_a?(ActiveRecord::Base) && value.new_record?
|
87
|
+
|
88
|
+
value.to_global_id.to_s
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def signed_params
|
95
|
+
message_verifier.generate(transformed_options)
|
96
|
+
end
|
97
|
+
|
98
|
+
def signed_controller
|
99
|
+
return unless controller.present?
|
100
|
+
|
101
|
+
message_verifier.generate(controller.to_s)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/futurism/channel.rb
CHANGED
@@ -15,14 +15,16 @@ module Futurism
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def receive(data)
|
18
|
-
resources = data.fetch_values("signed_params", "sgids", "signed_controllers", "urls") { |_key| Array.new(data["signed_params"].length, nil) }.transpose
|
18
|
+
resources = data.fetch_values("signed_params", "sgids", "signed_controllers", "urls", "broadcast_each") { |_key| Array.new(data["signed_params"].length, nil) }.transpose
|
19
19
|
|
20
20
|
resolver = Resolver::Resources.new(resource_definitions: resources, connection: connection, params: @params)
|
21
|
-
resolver.resolve do |selector, html|
|
21
|
+
resolver.resolve do |selector, html, broadcast_each|
|
22
22
|
cable_ready[stream_name].outer_html(
|
23
23
|
selector: selector,
|
24
24
|
html: html
|
25
25
|
)
|
26
|
+
|
27
|
+
cable_ready.broadcast if broadcast_each
|
26
28
|
end
|
27
29
|
|
28
30
|
cable_ready.broadcast
|
data/lib/futurism/channel.rb~
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module Futurism
|
2
2
|
class Channel < ActionCable::Channel::Base
|
3
3
|
include CableReady::Broadcaster
|
4
|
-
include Futurism::MessageVerifier
|
5
4
|
|
6
5
|
def stream_name
|
7
6
|
ids = connection.identifiers.map { |identifier| send(identifier).try(:id) || send(identifier) }
|
@@ -18,23 +17,8 @@ module Futurism
|
|
18
17
|
def receive(data)
|
19
18
|
resources = data.fetch_values("signed_params", "sgids", "signed_controllers", "urls") { |_key| Array.new(data["signed_params"].length, nil) }.transpose
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
GlobalID::Locator.locate_many_signed resources_with_sgids.map(&:second)
|
24
|
-
|
25
|
-
resources_without_sgids.each do |signed_params, sgid, signed_controller, url|
|
26
|
-
selector = "[data-signed-params='#{signed_params}']"
|
27
|
-
selector << "[data-sgid='#{sgid}']" if sgid.present?
|
28
|
-
|
29
|
-
controller = Resolver::Controller.from(signed_string: signed_controller)
|
30
|
-
renderer = Resolver::Controller::Renderer.for(controller: controller,
|
31
|
-
connection: connection,
|
32
|
-
url: url,
|
33
|
-
params: @params)
|
34
|
-
|
35
|
-
resource = lookup_resource(signed_params: signed_params, sgid: sgid)
|
36
|
-
html = renderer.render(resource)
|
37
|
-
|
20
|
+
resolver = Resolver::Resources.new(resource_definitions: resources, connection: connection, params: @params)
|
21
|
+
resolver.resolve do |selector, html|
|
38
22
|
cable_ready[stream_name].outer_html(
|
39
23
|
selector: selector,
|
40
24
|
html: html
|
@@ -43,15 +27,5 @@ module Futurism
|
|
43
27
|
|
44
28
|
cable_ready.broadcast
|
45
29
|
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def lookup_resource(signed_params:, sgid:)
|
50
|
-
return GlobalID::Locator.locate_signed(sgid) if sgid.present?
|
51
|
-
|
52
|
-
message_verifier
|
53
|
-
.verify(signed_params)
|
54
|
-
.deep_transform_values { |value| value.is_a?(String) && value.start_with?("gid://") ? GlobalID::Locator.locate(value) : value }
|
55
|
-
end
|
56
30
|
end
|
57
31
|
end
|
data/lib/futurism/helpers.rb
CHANGED
@@ -9,7 +9,11 @@ module Futurism
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
if block_given?
|
13
|
+
placeholder = capture(&block)
|
14
|
+
else
|
15
|
+
options[:eager] = true
|
16
|
+
end
|
13
17
|
|
14
18
|
if records_or_string.is_a?(ActiveRecord::Base) || records_or_string.is_a?(ActiveRecord::Relation)
|
15
19
|
futurize_active_record(records_or_string, extends: extends, placeholder: placeholder, **options)
|
@@ -24,33 +28,38 @@ module Futurism
|
|
24
28
|
def futurize_with_options(extends:, placeholder:, **options)
|
25
29
|
collection = options.delete(:collection)
|
26
30
|
if collection.nil?
|
27
|
-
|
31
|
+
WrappingFuturismElement.new(extends: extends, placeholder: placeholder, options: options).render
|
28
32
|
else
|
29
33
|
collection_class_name = collection.try(:klass).try(:name) || collection.first.class.to_s
|
30
|
-
as = options.delete(:as) || collection_class_name.
|
34
|
+
as = options.delete(:as) || collection_class_name.underscore
|
35
|
+
broadcast_each = options.delete(:broadcast_each) || false
|
31
36
|
collection.each_with_index.map { |record, index|
|
32
|
-
|
37
|
+
WrappingFuturismElement.new(extends: extends, placeholder: placeholder, options: options.deep_merge(
|
38
|
+
broadcast_each: broadcast_each,
|
39
|
+
locals: {as.to_sym => record, "#{as}_counter".to_sym => index}
|
40
|
+
)).render
|
33
41
|
}.join.html_safe
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
45
|
def futurize_active_record(records, extends:, placeholder:, **options)
|
38
46
|
Array(records).map { |record|
|
39
|
-
|
47
|
+
WrappingFuturismElement.new(extends: extends, options: options.merge(model: record), placeholder: placeholder).render
|
40
48
|
}.join.html_safe
|
41
49
|
end
|
42
50
|
|
43
51
|
# wraps functionality for rendering a futurism element
|
44
|
-
class
|
52
|
+
class WrappingFuturismElement
|
45
53
|
include ActionView::Helpers
|
46
54
|
include Futurism::MessageVerifier
|
47
55
|
|
48
|
-
attr_reader :extends, :placeholder, :html_options, :data_attributes, :model, :options, :eager, :controller
|
56
|
+
attr_reader :extends, :placeholder, :html_options, :data_attributes, :model, :options, :eager, :broadcast_each, :controller
|
49
57
|
|
50
58
|
def initialize(extends:, placeholder:, options:)
|
51
59
|
@extends = extends
|
52
60
|
@placeholder = placeholder
|
53
61
|
@eager = options.delete(:eager)
|
62
|
+
@broadcast_each = options.delete(:broadcast_each)
|
54
63
|
@controller = options.delete(:controller)
|
55
64
|
@html_options = options.delete(:html_options) || {}
|
56
65
|
@data_attributes = html_options.fetch(:data, {}).except(:sgid, :signed_params)
|
@@ -63,6 +72,7 @@ module Futurism
|
|
63
72
|
signed_params: signed_params,
|
64
73
|
sgid: model && model.to_sgid.to_s,
|
65
74
|
eager: eager.presence,
|
75
|
+
broadcast_each: broadcast_each.presence,
|
66
76
|
signed_controller: signed_controller
|
67
77
|
})
|
68
78
|
end
|
@@ -82,7 +92,10 @@ module Futurism
|
|
82
92
|
require_relative "shims/deep_transform_values" unless options.respond_to? :deep_transform_values
|
83
93
|
|
84
94
|
options.deep_transform_values do |value|
|
85
|
-
value
|
95
|
+
next(value) unless value.respond_to?(:to_global_id)
|
96
|
+
next(value) if value.is_a?(ActiveRecord::Base) && value.new_record?
|
97
|
+
|
98
|
+
value.to_global_id.to_s
|
86
99
|
end
|
87
100
|
end
|
88
101
|
|
data/lib/futurism/helpers.rb~
CHANGED
@@ -9,7 +9,11 @@ module Futurism
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
if block_given?
|
13
|
+
placeholder = capture(&block)
|
14
|
+
else
|
15
|
+
options[:eager] = true
|
16
|
+
end
|
13
17
|
|
14
18
|
if records_or_string.is_a?(ActiveRecord::Base) || records_or_string.is_a?(ActiveRecord::Relation)
|
15
19
|
futurize_active_record(records_or_string, extends: extends, placeholder: placeholder, **options)
|
@@ -24,24 +28,28 @@ module Futurism
|
|
24
28
|
def futurize_with_options(extends:, placeholder:, **options)
|
25
29
|
collection = options.delete(:collection)
|
26
30
|
if collection.nil?
|
27
|
-
|
31
|
+
WrappingFuturismElement.new(extends: extends, placeholder: placeholder, options: options).render
|
28
32
|
else
|
29
|
-
collection_class_name = collection.klass.name
|
30
|
-
as = options.delete(:as) || collection_class_name.
|
31
|
-
|
32
|
-
|
33
|
+
collection_class_name = collection.try(:klass).try(:name) || collection.first.class.to_s
|
34
|
+
as = options.delete(:as) || collection_class_name.underscore
|
35
|
+
broadcast_each = options.delete(:broadcast_each) || false
|
36
|
+
collection.each_with_index.map { |record, index|
|
37
|
+
WrappingFuturismElement.new(extends: extends, placeholder: placeholder, options: options.deep_merge(
|
38
|
+
broadcast_each: broadcast_each,
|
39
|
+
locals: {as.to_sym => record, "#{as}_counter".to_sym => index}
|
40
|
+
)).render
|
33
41
|
}.join.html_safe
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
45
|
def futurize_active_record(records, extends:, placeholder:, **options)
|
38
46
|
Array(records).map { |record|
|
39
|
-
|
47
|
+
WrappingFuturismElement.new(extends: extends, options: options.merge(model: record), placeholder: placeholder).render
|
40
48
|
}.join.html_safe
|
41
49
|
end
|
42
50
|
|
43
51
|
# wraps functionality for rendering a futurism element
|
44
|
-
class
|
52
|
+
class WrappingFuturismElement
|
45
53
|
include ActionView::Helpers
|
46
54
|
include Futurism::MessageVerifier
|
47
55
|
|
@@ -82,7 +90,10 @@ module Futurism
|
|
82
90
|
require_relative "shims/deep_transform_values" unless options.respond_to? :deep_transform_values
|
83
91
|
|
84
92
|
options.deep_transform_values do |value|
|
85
|
-
value
|
93
|
+
next(value) unless value.respond_to?(:to_global_id)
|
94
|
+
next(value) if value.is_a?(ActiveRecord::Base) && value.new_record?
|
95
|
+
|
96
|
+
value.to_global_id.to_s
|
86
97
|
end
|
87
98
|
end
|
88
99
|
|
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Futurism
|
2
4
|
module Resolver
|
3
5
|
class Controller
|
4
6
|
class Renderer
|
7
|
+
HTTP_METHODS = [:get, :post, :put, :patch, :delete]
|
8
|
+
|
5
9
|
def self.for(controller:, connection:, url:, params:)
|
6
10
|
new(controller: controller, connection: connection, url: url, params: params).renderer
|
7
11
|
end
|
@@ -30,7 +34,7 @@ module Futurism
|
|
30
34
|
path = ActionDispatch::Journey::Router::Utils.normalize_path(uri.path)
|
31
35
|
query_hash = Rack::Utils.parse_nested_query(uri.query)
|
32
36
|
|
33
|
-
path_params =
|
37
|
+
path_params = recognize_url(url) # use full url to be more likely to match a url with subdomain constraints
|
34
38
|
|
35
39
|
self.renderer =
|
36
40
|
renderer.new(
|
@@ -51,6 +55,21 @@ module Futurism
|
|
51
55
|
new_env = connection.env.merge(renderer.instance_variable_get(:@env))
|
52
56
|
renderer.instance_variable_set(:@env, new_env)
|
53
57
|
end
|
58
|
+
|
59
|
+
def recognize_url(url)
|
60
|
+
HTTP_METHODS.each do |http_method|
|
61
|
+
path = Rails.application.routes.recognize_path(url, method: http_method)
|
62
|
+
return path if path
|
63
|
+
rescue ActionController::RoutingError
|
64
|
+
# Route not matched, try next
|
65
|
+
end
|
66
|
+
|
67
|
+
warn "We were unable to find a matching rails route for '#{url}'. " \
|
68
|
+
"This may be because there are proc-based routing constraints for this particular url, or " \
|
69
|
+
"it truly is an unrecognizable url."
|
70
|
+
|
71
|
+
{}
|
72
|
+
end
|
54
73
|
end
|
55
74
|
end
|
56
75
|
end
|
@@ -3,7 +3,7 @@ module Futurism
|
|
3
3
|
class Resources
|
4
4
|
include Futurism::MessageVerifier
|
5
5
|
|
6
|
-
# resource definitions are an array of [signed_params, sgid, signed_controller, url]
|
6
|
+
# resource definitions are an array of [signed_params, sgid, signed_controller, url, broadcast_each]
|
7
7
|
def initialize(resource_definitions:, connection:, params:)
|
8
8
|
@connection = connection
|
9
9
|
@params = params
|
@@ -16,24 +16,34 @@ module Futurism
|
|
16
16
|
resolved_models.zip(@resources_with_sgids).each do |model, resource_definition|
|
17
17
|
html = renderer_for(resource_definition: resource_definition).render(model)
|
18
18
|
|
19
|
-
yield(resource_definition.selector, html)
|
19
|
+
yield(resource_definition.selector, html, resource_definition.broadcast_each)
|
20
20
|
end
|
21
21
|
|
22
22
|
@resources_without_sgids.each do |resource_definition|
|
23
23
|
resource = lookup_resource(resource_definition)
|
24
|
-
|
24
|
+
renderer = renderer_for(resource_definition: resource_definition)
|
25
|
+
html =
|
26
|
+
begin
|
27
|
+
renderer.render(resource)
|
28
|
+
rescue => exception
|
29
|
+
error_renderer.render(exception)
|
30
|
+
end
|
25
31
|
|
26
|
-
yield(resource_definition.selector, html)
|
32
|
+
yield(resource_definition.selector, html, resource_definition.broadcast_each)
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
30
36
|
private
|
31
37
|
|
38
|
+
def error_renderer
|
39
|
+
ErrorRenderer.new
|
40
|
+
end
|
41
|
+
|
32
42
|
class ResourceDefinition
|
33
43
|
attr_reader :signed_params, :sgid, :signed_controller, :url
|
34
44
|
|
35
45
|
def initialize(resource_definition)
|
36
|
-
@signed_params, @sgid, @signed_controller, @url = resource_definition
|
46
|
+
@signed_params, @sgid, @signed_controller, @url, @broadcast_each = resource_definition
|
37
47
|
end
|
38
48
|
|
39
49
|
def selector
|
@@ -45,6 +55,29 @@ module Futurism
|
|
45
55
|
def controller
|
46
56
|
Resolver::Controller.from(signed_string: @signed_controller)
|
47
57
|
end
|
58
|
+
|
59
|
+
def broadcast_each
|
60
|
+
@broadcast_each == "true"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ErrorRenderer
|
65
|
+
include ActionView::Helpers::TagHelper
|
66
|
+
|
67
|
+
def render(exception)
|
68
|
+
return "" unless render?
|
69
|
+
|
70
|
+
Futurism.logger.error(exception.to_s)
|
71
|
+
Futurism.logger.error(exception.backtrace)
|
72
|
+
|
73
|
+
tag.div { tag.span(exception.to_s) + tag.div(exception.backtrace.join("\n"), style: "display: none;") }
|
74
|
+
end
|
75
|
+
|
76
|
+
def render?
|
77
|
+
Rails.env.development? || Rails.env.test?
|
78
|
+
end
|
79
|
+
|
80
|
+
attr_accessor :output_buffer
|
48
81
|
end
|
49
82
|
|
50
83
|
def renderer_for(resource_definition:)
|
@@ -9,65 +9,89 @@ module Futurism
|
|
9
9
|
@params = params
|
10
10
|
@resources_with_sgids, @resources_without_sgids = resource_definitions
|
11
11
|
.partition { |signed_params, sgid, *| sgid.present? }
|
12
|
-
.map { |definition| ResourceDefinition.new(definition) }
|
12
|
+
.map { |partition| partition.map { |definition| ResourceDefinition.new(definition) } }
|
13
13
|
end
|
14
14
|
|
15
15
|
def resolve
|
16
16
|
resolved_models.zip(@resources_with_sgids).each do |model, resource_definition|
|
17
|
-
|
17
|
+
html = renderer_for(resource_definition: resource_definition).render(model)
|
18
18
|
|
19
|
-
selector
|
20
|
-
|
21
|
-
controller = Resolver::Controller.from(signed_string: signed_controller)
|
22
|
-
renderer = Resolver::Controller::Renderer.for(controller: controller,
|
23
|
-
connection: @connection,
|
24
|
-
url: url,
|
25
|
-
params: @params)
|
26
|
-
|
27
|
-
html = renderer.render(model)
|
28
|
-
|
29
|
-
yield(selector, html)
|
19
|
+
yield(resource_definition.selector, html)
|
30
20
|
end
|
31
21
|
|
32
|
-
@resources_without_sgids.each do |
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
22
|
+
@resources_without_sgids.each do |resource_definition|
|
23
|
+
resource = lookup_resource(resource_definition)
|
24
|
+
renderer = renderer_for(resource_definition: resource_definition)
|
25
|
+
html =
|
26
|
+
begin
|
27
|
+
renderer.render(resource)
|
28
|
+
rescue => exception
|
29
|
+
error_renderer.render(exception)
|
30
|
+
end
|
40
31
|
|
41
|
-
|
42
|
-
html = renderer.render(resource)
|
43
|
-
|
44
|
-
yield(selector, html)
|
32
|
+
yield(resource_definition.selector, html)
|
45
33
|
end
|
46
34
|
end
|
47
35
|
|
48
36
|
private
|
49
37
|
|
38
|
+
def error_renderer
|
39
|
+
ErrorRenderer.new
|
40
|
+
end
|
41
|
+
|
50
42
|
class ResourceDefinition
|
43
|
+
attr_reader :signed_params, :sgid, :signed_controller, :url
|
44
|
+
|
51
45
|
def initialize(resource_definition)
|
52
46
|
@signed_params, @sgid, @signed_controller, @url = resource_definition
|
53
47
|
end
|
48
|
+
|
49
|
+
def selector
|
50
|
+
selector = "[data-signed-params='#{@signed_params}']"
|
51
|
+
selector << "[data-sgid='#{@sgid}']" if @sgid.present?
|
52
|
+
selector
|
53
|
+
end
|
54
|
+
|
55
|
+
def controller
|
56
|
+
Resolver::Controller.from(signed_string: @signed_controller)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class ErrorRenderer
|
61
|
+
include ActionView::Helpers::TagHelper
|
62
|
+
|
63
|
+
def render(exception)
|
64
|
+
return "" unless render?
|
65
|
+
|
66
|
+
Futurism.logger.error(exception.to_s)
|
67
|
+
Futurism.logger.error(exception.backtrace)
|
68
|
+
|
69
|
+
tag.div { tag.span(exception.to_s) + tag.div(exception.backtrace.join("\n"), style: "display: none;") }
|
70
|
+
end
|
71
|
+
|
72
|
+
def render?
|
73
|
+
Rails.env.development? || Rails.env.test?
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_accessor :output_buffer
|
77
|
+
end
|
78
|
+
|
79
|
+
def renderer_for(resource_definition:)
|
80
|
+
Resolver::Controller::Renderer.for(controller: resource_definition.controller,
|
81
|
+
connection: @connection,
|
82
|
+
url: resource_definition.url,
|
83
|
+
params: @params)
|
54
84
|
end
|
55
85
|
|
56
86
|
def resolved_models
|
57
|
-
GlobalID::Locator.locate_many_signed @resources_with_sgids.map(&:
|
87
|
+
GlobalID::Locator.locate_many_signed @resources_with_sgids.map(&:sgid)
|
58
88
|
end
|
59
89
|
|
60
|
-
def lookup_resource(
|
90
|
+
def lookup_resource(resource_definition)
|
61
91
|
message_verifier
|
62
|
-
.verify(signed_params)
|
92
|
+
.verify(resource_definition.signed_params)
|
63
93
|
.deep_transform_values { |value| value.is_a?(String) && value.start_with?("gid://") ? GlobalID::Locator.locate(value) : value }
|
64
94
|
end
|
65
|
-
|
66
|
-
def selector_for(signed_params:, sgid:)
|
67
|
-
selector = "[data-signed-params='#{signed_params}']"
|
68
|
-
selector << "[data-sgid='#{sgid}']" if sgid.present?
|
69
|
-
selector
|
70
|
-
end
|
71
95
|
end
|
72
96
|
end
|
73
97
|
end
|
data/lib/futurism/version.rb
CHANGED
data/lib/futurism/version.rb~
CHANGED
data/lib/futurism.rb
CHANGED
@@ -21,7 +21,10 @@ module Futurism
|
|
21
21
|
(@@default_controller || "::ApplicationController").to_s.constantize
|
22
22
|
end
|
23
23
|
|
24
|
-
ActiveSupport.on_load(:action_view)
|
24
|
+
ActiveSupport.on_load(:action_view) do
|
25
25
|
include Futurism::Helpers
|
26
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
mattr_accessor :logger
|
29
|
+
self.logger ||= Rails.logger ? Rails.logger.new : Logger.new($stdout)
|
27
30
|
end
|
@@ -3,7 +3,7 @@ require "fileutils"
|
|
3
3
|
namespace :futurism do
|
4
4
|
desc "Let's look into a brighter future with futurism and CableReady"
|
5
5
|
task install: :environment do
|
6
|
-
system "yarn add @
|
6
|
+
system "yarn add @stimulus_reflex/futurism"
|
7
7
|
|
8
8
|
filepath = %w[
|
9
9
|
app/javascript/channels/index.js
|
@@ -20,7 +20,7 @@ namespace :futurism do
|
|
20
20
|
|
21
21
|
unless lines.find { |line| line.start_with?("import * as Futurism") }
|
22
22
|
matches = lines.select { |line| line =~ /\A(require|import)/ }
|
23
|
-
lines.insert lines.index(matches.last).to_i + 1, "import * as Futurism from '@
|
23
|
+
lines.insert lines.index(matches.last).to_i + 1, "import * as Futurism from '@stimulus_reflex/futurism'\n"
|
24
24
|
end
|
25
25
|
|
26
26
|
unless lines.find { |line| line.start_with?("import consumer") }
|
@@ -1,4 +1,39 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
namespace :futurism do
|
4
|
+
desc "Let's look into a brighter future with futurism and CableReady"
|
5
|
+
task install: :environment do
|
6
|
+
system "yarn add @minthesize/futurism"
|
7
|
+
|
8
|
+
filepath = %w[
|
9
|
+
app/javascript/channels/index.js
|
10
|
+
app/javascript/channels/index.ts
|
11
|
+
app/javascript/packs/application.js
|
12
|
+
app/javascript/packs/application.ts
|
13
|
+
]
|
14
|
+
.select { |path| File.exist?(path) }
|
15
|
+
.map { |path| Rails.root.join(path) }
|
16
|
+
.first
|
17
|
+
|
18
|
+
puts "Updating #{filepath}"
|
19
|
+
lines = File.open(filepath, "r") { |f| f.readlines }
|
20
|
+
|
21
|
+
unless lines.find { |line| line.start_with?("import * as Futurism") }
|
22
|
+
matches = lines.select { |line| line =~ /\A(require|import)/ }
|
23
|
+
lines.insert lines.index(matches.last).to_i + 1, "import * as Futurism from '@minthesize/futurism'\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
unless lines.find { |line| line.start_with?("import consumer") }
|
27
|
+
matches = lines.select { |line| line =~ /\A(require|import)/ }
|
28
|
+
lines.insert lines.index(matches.last).to_i + 1, "import consumer from '../channels/consumer'\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
initialize_line = lines.find { |line| line.start_with?("Futurism.initializeElements") }
|
32
|
+
lines << "Futurism.initializeElements()\n" unless initialize_line
|
33
|
+
|
34
|
+
subscribe_line = lines.find { |line| line.start_with?("Futurism.createSubscription") }
|
35
|
+
lines << "Futurism.createSubscription(consumer)\n" unless subscribe_line
|
36
|
+
|
37
|
+
File.open(filepath, "w") { |f| f.write lines.join }
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: futurism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julian Rubisch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- config/routes.rb
|
151
151
|
- lib/futurism.rb
|
152
152
|
- lib/futurism.rb~
|
153
|
+
- lib/futurism/#helpers.rb#
|
153
154
|
- lib/futurism/channel.rb
|
154
155
|
- lib/futurism/channel.rb~
|
155
156
|
- lib/futurism/engine.rb
|
@@ -167,7 +168,7 @@ files:
|
|
167
168
|
- lib/futurism/version.rb~
|
168
169
|
- lib/tasks/futurism_tasks.rake
|
169
170
|
- lib/tasks/futurism_tasks.rake~
|
170
|
-
homepage: https://github.com/
|
171
|
+
homepage: https://github.com/stimulusreflex/futurism
|
171
172
|
licenses:
|
172
173
|
- MIT
|
173
174
|
metadata: {}
|