keynote 1.1.1 → 2.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 +5 -5
- data/CHANGELOG.md +71 -27
- data/{LICENSE → LICENSE.txt} +2 -6
- data/README.md +119 -47
- data/lib/generators/presenter_generator.rb +16 -24
- data/lib/keynote/cache.rb +1 -1
- data/lib/keynote/controller.rb +4 -5
- data/lib/keynote/core.rb +64 -0
- data/lib/keynote/helper.rb +4 -5
- data/lib/keynote/inline.rb +51 -109
- data/lib/keynote/presenter.rb +13 -19
- data/lib/keynote/railtie.rb +7 -24
- data/lib/keynote/rumble.rb +21 -12
- data/lib/keynote/testing/{minitest_rails.rb → minitest.rb} +1 -2
- data/lib/keynote/testing/rspec.rb +5 -5
- data/lib/keynote/testing/test_present_method.rb +2 -2
- data/lib/keynote/testing/test_unit.rb +1 -1
- data/lib/keynote/version.rb +2 -2
- data/lib/keynote.rb +7 -65
- metadata +68 -96
- data/.editorconfig +0 -14
- data/.gitignore +0 -18
- data/.travis.yml +0 -11
- data/.yardopts +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -21
- data/keynote.gemspec +0 -37
- data/lib/generators/templates/keynote_mini_test_unit.rb +0 -11
- data/lib/keynote/testing/minitest_rails.rake +0 -7
- data/scenarios/rails31.docker-compose.yml +0 -15
- data/scenarios/rails31.dockerfile +0 -5
- data/scenarios/rails31.gemfile +0 -7
- data/scenarios/rails32.docker-compose.yml +0 -15
- data/scenarios/rails32.dockerfile +0 -5
- data/scenarios/rails32.gemfile +0 -6
- data/scenarios/rails40.docker-compose.yml +0 -15
- data/scenarios/rails40.dockerfile +0 -5
- data/scenarios/rails40.gemfile +0 -6
- data/scenarios/rails41.docker-compose.yml +0 -15
- data/scenarios/rails41.dockerfile +0 -5
- data/scenarios/rails41.gemfile +0 -6
- data/scenarios/rails42.docker-compose.yml +0 -15
- data/scenarios/rails42.dockerfile +0 -5
- data/scenarios/rails42.gemfile +0 -6
- data/scenarios/rails50.docker-compose.yml +0 -15
- data/scenarios/rails50.dockerfile +0 -5
- data/scenarios/rails50.gemfile +0 -6
- data/scenarios/rails51.docker-compose.yml +0 -15
- data/scenarios/rails51.dockerfile +0 -5
- data/scenarios/rails51.gemfile +0 -6
- data/scenarios.yml +0 -25
- data/spec/benchmarks.rb +0 -73
- data/spec/generator_spec.rb +0 -159
- data/spec/helper.rb +0 -90
- data/spec/inline_spec.rb +0 -157
- data/spec/keynote_spec.rb +0 -130
- data/spec/presenter_spec.rb +0 -179
- data/spec/railtie_spec.rb +0 -33
- data/spec/rumble_spec.rb +0 -277
- data/spec/test_case_spec.rb +0 -12
- /data/lib/generators/templates/{keynote_mini_test_spec.rb → keynote_mini_test_spec.rb.tt} +0 -0
- /data/lib/generators/templates/{keynote_test_unit.rb → keynote_mini_test_unit.rb.tt} +0 -0
- /data/lib/generators/templates/{keynote_presenter.rb → keynote_presenter.rb.tt} +0 -0
- /data/lib/generators/templates/{keynote_rspec.rb → keynote_rspec.rb.tt} +0 -0
data/lib/keynote/inline.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: false
|
2
2
|
|
3
3
|
require "action_view"
|
4
|
-
require "thread"
|
5
4
|
|
6
5
|
module Keynote
|
7
6
|
# The `Inline` mixin lets you write inline templates as comments inside the
|
@@ -11,15 +10,18 @@ module Keynote
|
|
11
10
|
# ## Basic usage
|
12
11
|
#
|
13
12
|
# After extending the `Keynote::Inline` module in your presenter class, you
|
14
|
-
# can generate HTML by calling the `erb` method and
|
15
|
-
#
|
13
|
+
# can generate HTML by calling the `erb` method and passing a template as a string
|
14
|
+
# to it:
|
16
15
|
#
|
17
16
|
# def link
|
18
|
-
# erb
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
17
|
+
# erb do
|
18
|
+
# <<~ERB
|
19
|
+
# <%= link_to user_url(current_user) do %>
|
20
|
+
# <%= image_tag("image1.jpg") %>
|
21
|
+
# <%= image_tag("image2.jpg") %>
|
22
|
+
# <% end %>
|
23
|
+
# ERB
|
24
|
+
# end
|
23
25
|
# end
|
24
26
|
#
|
25
27
|
# Calling this method renders the ERB template, including passing the calls
|
@@ -28,23 +30,15 @@ module Keynote
|
|
28
30
|
#
|
29
31
|
# ## Passing variables
|
30
32
|
#
|
31
|
-
#
|
32
|
-
# template. The easiest is to pass the `binding` object into the template
|
33
|
-
# method, giving access to all local variables:
|
33
|
+
# You can pass locals as keyword arguments to the `erb` method:
|
34
34
|
#
|
35
|
-
# def
|
35
|
+
# def with_locals
|
36
36
|
# x = 1
|
37
37
|
# y = 2
|
38
38
|
#
|
39
|
-
# erb
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# You can also pass a hash of variable names and values instead:
|
44
|
-
#
|
45
|
-
# def local_binding
|
46
|
-
# erb x: 1, y: 2
|
47
|
-
# # <%= x + y %>
|
39
|
+
# erb(x:, y:) do
|
40
|
+
# %q(<%= x + y %>)
|
41
|
+
# end
|
48
42
|
# end
|
49
43
|
#
|
50
44
|
# ## The `inline` method
|
@@ -83,18 +77,22 @@ module Keynote
|
|
83
77
|
# def header
|
84
78
|
# full_name = "#{user.first_name} #{user.last_name}"
|
85
79
|
#
|
86
|
-
# haml
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
80
|
+
# haml(full_name:) do
|
81
|
+
# <<~HAML
|
82
|
+
# div#header
|
83
|
+
# h1= full_name
|
84
|
+
# h3= user.most_recent_status
|
85
|
+
# HAML
|
86
|
+
# end
|
90
87
|
# end
|
91
88
|
# end
|
92
89
|
def inline(*formats)
|
93
90
|
require "action_view/context"
|
94
91
|
|
95
92
|
Array(formats).each do |format|
|
96
|
-
define_method format do
|
97
|
-
|
93
|
+
define_method format do |**locals, &block|
|
94
|
+
raise ArgumentError, "You must pass a block to the ##{format} method" unless block
|
95
|
+
Renderer.new(self, locals, caller_locations(1, 1).first, block.call, format).render
|
98
96
|
end
|
99
97
|
end
|
100
98
|
end
|
@@ -103,45 +101,39 @@ module Keynote
|
|
103
101
|
# base class.
|
104
102
|
def self.extended(base)
|
105
103
|
base.inline :erb
|
104
|
+
base.include InstanceMethods
|
105
|
+
end
|
106
|
+
|
107
|
+
module InstanceMethods
|
108
|
+
# A callback for Action View: https://github.com/rails/rails/blob/a32eab53a58540b9ca57da429c5f64564db43126/actionview/lib/action_view/base.rb#L261
|
109
|
+
def _run(method, template, locals, buffer, add_to_stack: true, has_strict_locals: false, &block)
|
110
|
+
old_output_buffer, old_virtual_path, old_template = @output_buffer, @virtual_path, @current_template
|
111
|
+
@current_template = template if add_to_stack
|
112
|
+
@output_buffer = buffer
|
113
|
+
public_send(method, locals, buffer, &block)
|
114
|
+
ensure
|
115
|
+
@output_buffer, @virtual_path, @current_template = old_output_buffer, old_virtual_path, old_template
|
116
|
+
end
|
106
117
|
end
|
107
118
|
|
108
119
|
# @private
|
109
120
|
class Renderer
|
110
|
-
def initialize(presenter, locals,
|
121
|
+
def initialize(presenter, locals, loc, source, format)
|
111
122
|
@presenter = presenter
|
112
|
-
@locals =
|
113
|
-
@template = Cache.fetch(
|
123
|
+
@locals = locals
|
124
|
+
@template = Cache.fetch(loc.path, loc.lineno, source, format, locals)
|
114
125
|
end
|
115
126
|
|
116
127
|
def render
|
117
128
|
@template.render(@presenter, @locals)
|
118
129
|
end
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def extract_locals(locals)
|
123
|
-
return locals unless locals.is_a?(Binding)
|
124
|
-
|
125
|
-
Hash[locals.eval("local_variables").map do |local|
|
126
|
-
[local, locals.eval(local.to_s)]
|
127
|
-
end]
|
128
|
-
end
|
129
|
-
|
130
|
-
def parse_caller(caller_line)
|
131
|
-
file, rest = caller_line.split ":", 2
|
132
|
-
line, _ = rest.split " ", 2
|
133
|
-
|
134
|
-
[file.strip, line.to_i]
|
135
|
-
end
|
136
130
|
end
|
137
131
|
|
138
132
|
# @private
|
139
133
|
class Cache
|
140
|
-
|
141
|
-
|
142
|
-
def self.fetch(source_file, line, format, locals)
|
134
|
+
def self.fetch(source_file, line, source, format, locals)
|
143
135
|
instance = (Thread.current[:_keynote_template_cache] ||= Cache.new)
|
144
|
-
instance.fetch(source_file, line, format, locals)
|
136
|
+
instance.fetch(source_file, line, source, format, locals)
|
145
137
|
end
|
146
138
|
|
147
139
|
def self.reset
|
@@ -152,18 +144,17 @@ module Keynote
|
|
152
144
|
@cache = {}
|
153
145
|
end
|
154
146
|
|
155
|
-
def fetch(source_file, line, format, locals)
|
147
|
+
def fetch(source_file, line, source, format, locals)
|
156
148
|
local_names = locals.keys.sort
|
157
|
-
cache_key
|
158
|
-
new_mtime
|
149
|
+
cache_key = ["#{source_file}:#{line}", *local_names].freeze
|
150
|
+
new_mtime = File.mtime(source_file).to_f
|
159
151
|
|
160
152
|
template, mtime = @cache[cache_key]
|
161
153
|
|
162
154
|
if new_mtime != mtime
|
163
|
-
source =
|
164
|
-
|
155
|
+
source = unindent(source.chomp)
|
165
156
|
template = Template.new(source, cache_key[0],
|
166
|
-
handler_for_format(format), locals: local_names)
|
157
|
+
handler_for_format(format), format:, locals: local_names)
|
167
158
|
|
168
159
|
@cache[cache_key] = [template, new_mtime]
|
169
160
|
end
|
@@ -173,20 +164,6 @@ module Keynote
|
|
173
164
|
|
174
165
|
private
|
175
166
|
|
176
|
-
def read_template(source_file, line_num)
|
177
|
-
result = ""
|
178
|
-
|
179
|
-
File.foreach(source_file).drop(line_num).each do |line|
|
180
|
-
if line =~ COMMENTED_LINE
|
181
|
-
result << $1 << "\n"
|
182
|
-
else
|
183
|
-
break
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
unindent result.chomp
|
188
|
-
end
|
189
|
-
|
190
167
|
def handler_for_format(format)
|
191
168
|
ActionView::Template.handler_for_extension(format.to_s)
|
192
169
|
end
|
@@ -203,39 +180,12 @@ module Keynote
|
|
203
180
|
end
|
204
181
|
end
|
205
182
|
|
206
|
-
text.gsub(/^#{margin}/,
|
183
|
+
text.gsub(/^#{margin}/, " " * left_padding)
|
207
184
|
end
|
208
185
|
end
|
209
186
|
|
210
187
|
# @private
|
211
|
-
class
|
212
|
-
# Older versions of Rails don't have this mutex, but we probably want it,
|
213
|
-
# so let's make sure it's there.
|
214
|
-
def initialize(*)
|
215
|
-
super
|
216
|
-
@compile_mutex = Mutex.new
|
217
|
-
end
|
218
|
-
|
219
|
-
# The only difference between this #compile! and the normal one is that
|
220
|
-
# we call `view.class` instead of `view.singleton_class`, so that the
|
221
|
-
# template method gets defined as an instance method on the presenter
|
222
|
-
# and therefore sticks around between presenter instances.
|
223
|
-
def compile!(view)
|
224
|
-
return if @compiled
|
225
|
-
|
226
|
-
@compile_mutex.synchronize do
|
227
|
-
return if @compiled
|
228
|
-
|
229
|
-
compile(view, view.class)
|
230
|
-
|
231
|
-
@source = nil if defined?(@virtual_path) && @virtual_path
|
232
|
-
@compiled = true
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
# @private
|
238
|
-
class TemplateFor42AndHigher < ActionView::Template
|
188
|
+
class Template < ActionView::Template
|
239
189
|
# The only difference between this #compile! and the normal one is that
|
240
190
|
# we call `view.class` instead of `view.singleton_class`, so that the
|
241
191
|
# template method gets defined as an instance method on the presenter
|
@@ -253,13 +203,5 @@ module Keynote
|
|
253
203
|
end
|
254
204
|
end
|
255
205
|
end
|
256
|
-
|
257
|
-
if Rails.version.to_f < 4.2
|
258
|
-
# @private
|
259
|
-
Template = TemplateFor41AndLower
|
260
|
-
else
|
261
|
-
# @private
|
262
|
-
Template = TemplateFor42AndHigher
|
263
|
-
end
|
264
206
|
end
|
265
207
|
end
|
data/lib/keynote/presenter.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Keynote
|
4
4
|
# Keynote::Presenter is a base class for presenters, objects that encapsulate
|
@@ -36,10 +36,10 @@ module Keynote
|
|
36
36
|
objects.unshift :view
|
37
37
|
attr_reader(*objects)
|
38
38
|
|
39
|
-
param_list = objects.join(
|
40
|
-
ivar_list
|
39
|
+
param_list = objects.join(", ")
|
40
|
+
ivar_list = objects.map { "@#{it}" }.join(", ")
|
41
41
|
|
42
|
-
class_eval <<-RUBY
|
42
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
43
43
|
def initialize(#{param_list}) # def initialize(view, foo)
|
44
44
|
#{ivar_list} = #{param_list} # @view, @foo = view, foo
|
45
45
|
end # end
|
@@ -48,9 +48,7 @@ module Keynote
|
|
48
48
|
|
49
49
|
# Define a more complete set of HTML5 tag methods. The extra tags are
|
50
50
|
# listed in {Keynote::Rumble::COMPLETE}.
|
51
|
-
def use_html_5_tags
|
52
|
-
Rumble.use_html_5_tags(self)
|
53
|
-
end
|
51
|
+
def use_html_5_tags = Rumble.use_html_5_tags(self)
|
54
52
|
|
55
53
|
# List the object names this presenter wraps. The default is an empty
|
56
54
|
# array; calling `presents :foo, :bar` in the presenter's class body will
|
@@ -74,15 +72,15 @@ module Keynote
|
|
74
72
|
|
75
73
|
# Instantiate another presenter.
|
76
74
|
# @see Keynote.present
|
77
|
-
def present(
|
78
|
-
Keynote.present(@view,
|
75
|
+
def present(...)
|
76
|
+
Keynote.present(@view, ...)
|
79
77
|
end
|
80
|
-
|
78
|
+
alias_method :k, :present
|
81
79
|
|
82
80
|
# @private
|
83
81
|
def inspect
|
84
82
|
objects = self.class.object_names
|
85
|
-
render
|
83
|
+
render = proc { |name| "#{name}: #{send(name).inspect}" }
|
86
84
|
|
87
85
|
if objects.any?
|
88
86
|
"#<#{self.class} #{objects.map(&render).join(", ")}>"
|
@@ -105,9 +103,9 @@ module Keynote
|
|
105
103
|
# "#{h author.name} — #{h blog_post.title}".html_safe
|
106
104
|
# end
|
107
105
|
# end
|
108
|
-
def method_missing(method_name,
|
106
|
+
def method_missing(method_name, ...)
|
109
107
|
if @view.respond_to?(method_name, true)
|
110
|
-
@view.send(method_name,
|
108
|
+
@view.send(method_name, ...)
|
111
109
|
else
|
112
110
|
super
|
113
111
|
end
|
@@ -116,16 +114,12 @@ module Keynote
|
|
116
114
|
# @private
|
117
115
|
# We have to make a logger method available so that ActionView::Template
|
118
116
|
# can safely treat a presenter as a view object.
|
119
|
-
def logger
|
120
|
-
Rails.logger
|
121
|
-
end
|
117
|
+
def logger = Rails.logger
|
122
118
|
|
123
119
|
private
|
124
120
|
|
125
121
|
# We have to explicitly proxy `#capture` because ActiveSupport creates a
|
126
122
|
# `Kernel#capture` method.
|
127
|
-
def capture(
|
128
|
-
@view.capture(*args, &block)
|
129
|
-
end
|
123
|
+
def capture(...) = @view.capture(...)
|
130
124
|
end
|
131
125
|
end
|
data/lib/keynote/railtie.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "rails/railtie"
|
4
4
|
|
5
5
|
module Keynote
|
6
6
|
# @private
|
7
7
|
class Railtie < Rails::Railtie
|
8
8
|
config.after_initialize do |app|
|
9
|
-
add_presenters_to_paths(app)
|
10
9
|
load_test_integration
|
11
10
|
end
|
12
11
|
|
@@ -22,31 +21,15 @@ module Keynote
|
|
22
21
|
include Keynote::Controller
|
23
22
|
end
|
24
23
|
|
25
|
-
rake_tasks do
|
26
|
-
if defined?(MiniTest::Rails)
|
27
|
-
load File.expand_path("../testing/minitest_rails.rake", __FILE__)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.add_presenters_to_paths(app)
|
32
|
-
if ::Rails.version.to_f >= 4
|
33
|
-
app.config.paths.add 'app/presenters'
|
34
|
-
else
|
35
|
-
app.config.paths.add 'app/presenters', :eager_load => true
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
24
|
def self.load_test_integration
|
40
25
|
if defined?(RSpec::Rails)
|
41
|
-
require
|
42
|
-
end
|
43
|
-
|
44
|
-
if defined?(MiniTest::Rails)
|
45
|
-
require 'keynote/testing/minitest_rails'
|
26
|
+
require "keynote/testing/rspec"
|
46
27
|
end
|
47
28
|
|
48
|
-
|
49
|
-
|
29
|
+
begin
|
30
|
+
::ActionView::TestCase # rubocop:disable Lint/Void
|
31
|
+
require "keynote/testing/minitest"
|
32
|
+
rescue
|
50
33
|
end
|
51
34
|
end
|
52
35
|
end
|
data/lib/keynote/rumble.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: false
|
2
2
|
|
3
3
|
module Keynote
|
4
4
|
# HTML markup in Ruby.
|
@@ -189,7 +189,7 @@ module Keynote
|
|
189
189
|
tags.each do |tag|
|
190
190
|
sc = SELFCLOSING.include?(tag).inspect
|
191
191
|
|
192
|
-
base.class_eval <<-RUBY
|
192
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
193
193
|
def #{tag}(*args, &blk) # def a(*args, &blk)
|
194
194
|
rumble_tag :#{tag}, #{sc}, *args, &blk # rumble_tag :a, false, *args, &blk
|
195
195
|
end # end
|
@@ -243,17 +243,19 @@ module Keynote
|
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
246
|
+
def respond_to_missing?(name, include_private = false)
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
246
250
|
def method_missing(name, content = nil, attrs = nil, &blk)
|
247
251
|
name = name.to_s
|
248
252
|
|
249
|
-
if name[-1] ==
|
253
|
+
if name[-1] == "!"
|
250
254
|
attributes[:id] = name[0..-2]
|
255
|
+
elsif attributes.has_key?(:class)
|
256
|
+
attributes[:class] += " #{name}"
|
251
257
|
else
|
252
|
-
|
253
|
-
attributes[:class] += " #{name}"
|
254
|
-
else
|
255
|
-
attributes[:class] = name
|
256
|
-
end
|
258
|
+
attributes[:class] = name
|
257
259
|
end
|
258
260
|
|
259
261
|
insert(content, attrs, &blk)
|
@@ -292,8 +294,13 @@ module Keynote
|
|
292
294
|
raise $!
|
293
295
|
end
|
294
296
|
|
295
|
-
def to_ary
|
296
|
-
|
297
|
+
def to_ary
|
298
|
+
nil
|
299
|
+
end
|
300
|
+
|
301
|
+
def to_str
|
302
|
+
to_s
|
303
|
+
end
|
297
304
|
|
298
305
|
def html_safe?
|
299
306
|
true
|
@@ -313,7 +320,9 @@ module Keynote
|
|
313
320
|
end
|
314
321
|
end
|
315
322
|
|
316
|
-
def inspect
|
323
|
+
def inspect
|
324
|
+
to_s.inspect
|
325
|
+
end
|
317
326
|
|
318
327
|
private
|
319
328
|
|
@@ -344,7 +353,7 @@ module Keynote
|
|
344
353
|
Rumble.html_escape(value)
|
345
354
|
end
|
346
355
|
|
347
|
-
res << " #{name}=\"#{value.gsub('"'
|
356
|
+
res << " #{name}=\"#{value.gsub('"', """)}\""
|
348
357
|
res
|
349
358
|
end
|
350
359
|
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Mutually exclusive with the Keynote::TestCase defined in
|
4
4
|
# keynote/testing/test_unit. This is kind of icky but consistent with how
|
5
5
|
# MT::R itself replaces the Rails test case classes.
|
6
6
|
|
7
|
-
require "minitest/rails"
|
8
7
|
require "keynote/testing/test_present_method"
|
9
8
|
|
10
9
|
module Keynote
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rspec/core"
|
4
4
|
require "keynote/testing/test_present_method"
|
@@ -16,11 +16,11 @@ end
|
|
16
16
|
RSpec.configure do |config|
|
17
17
|
if RSpec::Core::Version::STRING.starts_with?("3")
|
18
18
|
config.include Keynote::ExampleGroup,
|
19
|
-
:
|
20
|
-
:
|
19
|
+
type: :presenter,
|
20
|
+
file_path: %r{spec.presenters}
|
21
21
|
else
|
22
22
|
config.include Keynote::ExampleGroup,
|
23
|
-
:
|
24
|
-
:
|
23
|
+
type: :presenter,
|
24
|
+
example_group: {file_path: %r{spec.presenters}}
|
25
25
|
end
|
26
26
|
end
|
data/lib/keynote/version.rb
CHANGED
data/lib/keynote.rb
CHANGED
@@ -1,73 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ruby-next"
|
4
|
+
require "ruby-next/language/setup"
|
5
|
+
RubyNext::Language.setup_gem_load_path(transpile: true)
|
6
|
+
|
7
|
+
require "keynote/core"
|
3
8
|
require "keynote/version"
|
4
9
|
require "keynote/rumble"
|
5
10
|
require "keynote/inline"
|
6
11
|
require "keynote/presenter"
|
7
12
|
require "keynote/controller"
|
8
13
|
require "keynote/helper"
|
9
|
-
require "keynote/railtie"
|
14
|
+
require "keynote/railtie" if defined?(Rails::Railtie)
|
10
15
|
require "keynote/cache"
|
11
|
-
|
12
|
-
# Keynote is a library for defining and instantiating presenters,
|
13
|
-
# objects that encapsulate view logic.
|
14
|
-
#
|
15
|
-
# @see file:README.md
|
16
|
-
module Keynote
|
17
|
-
class << self
|
18
|
-
# Create or retrieve a presenter wrapping zero or more objects.
|
19
|
-
# If a block is given, yield the presenter into it.
|
20
|
-
#
|
21
|
-
# The first parameter is a Rails view context, but you'll usually access
|
22
|
-
# this method through `Keynote::Helper#present`,
|
23
|
-
# `Keynote::Controller#present`, or `Keynote::Presenter#present`, all of
|
24
|
-
# which handle the view context parameter automatically.
|
25
|
-
#
|
26
|
-
# @see Keynote::Helper#present
|
27
|
-
# @see Keynote::Controller#present
|
28
|
-
# @see Keynote::Presenter#present
|
29
|
-
#
|
30
|
-
# @overload present(view, *objects)
|
31
|
-
# Return a presenter wrapping the given objects. The type of the
|
32
|
-
# presenter will be inferred from the type of the first object.
|
33
|
-
# @example
|
34
|
-
# present(view, MyModel.new) # => #<MyModelPresenter:0x0001>
|
35
|
-
# @param [ActionView::Base] view
|
36
|
-
# @param [Array] objects
|
37
|
-
# @return [Keynote::Presenter]
|
38
|
-
#
|
39
|
-
# @overload present(view, presenter_name, *objects)
|
40
|
-
# Return a presenter wrapping the given objects. The type of the
|
41
|
-
# presenter is specified in underscore form by the first parameter.
|
42
|
-
# @example
|
43
|
-
# present(view, :foo_bar, MyModel.new) # => #<FooBarPresenter:0x0002>
|
44
|
-
# @param [ActionView::Base] view
|
45
|
-
# @param [Symbol, String] presenter_name
|
46
|
-
# @param [Array] objects
|
47
|
-
# @return [Keynote::Presenter]
|
48
|
-
#
|
49
|
-
def present(view, *objects)
|
50
|
-
if objects[0].is_a?(Symbol) || objects[0].is_a?(String)
|
51
|
-
name = objects.shift
|
52
|
-
else
|
53
|
-
name = presenter_name_from_object(objects[0])
|
54
|
-
end
|
55
|
-
|
56
|
-
Cache.fetch(name, view, *objects) do
|
57
|
-
presenter_from_name(name).new(view, *objects).tap do |presenter|
|
58
|
-
yield presenter if block_given?
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def presenter_name_from_object(object)
|
66
|
-
object.class.to_s.underscore
|
67
|
-
end
|
68
|
-
|
69
|
-
def presenter_from_name(name)
|
70
|
-
"#{name.to_s.camelize}Presenter".constantize
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|