rubyoshka 0.4 → 0.5

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: 6c084b7ff1e4a364ea95df6fa3824c1a67a190aae85c8ad50812132ef7acd5cf
4
- data.tar.gz: 8b04fd36caf85ca4dc7883f2efad96ed53753d5b59548e19a9a3c5ec85f6fa28
3
+ metadata.gz: aabb46d1744db33af049b11eec91a9e18a938aea5391ab2f22e41c0bccce77ae
4
+ data.tar.gz: 7d1a473f5c25ab35f38d0886dee156f2da38bce9306cb48a4e39e47d6d2e818d
5
5
  SHA512:
6
- metadata.gz: 27c7bafa5f1851982ee05ccf9f90e1513c4b426217531f6daa205ce872ad57be9c672ba35ce1e5f0a6b882aa93dbf3987dab2375282e0bda22c897df1cf2ff5f
7
- data.tar.gz: 8a35f8f8ef434e21a48208d079d62acb4df497d6a44234caee41c4a1df92de8d20c8bc3329ce624eed2691fde5205961681b4a8ebd2e80966b99ee65e58c8b4f
6
+ metadata.gz: c5c43c9e8bb8f0b2a076a2a607ce3d735575748be1a6998dedb38ef795bfe3a8a33f2d3039c5ba379085b2750929966d4a9f41201651196dc2c1e5ea280c21c1
7
+ data.tar.gz: 120ad28457f4c3c1775de5d2b542d365a3abb5fdcdf01946097b251dd1830eaee7d2d6bc63bf1fe72c195073e80b9c2e4b3b0d9bddc2445c81c31d45aa9157a2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ 0.5 2021-02-27
2
+ --------------
3
+
4
+ * Add support for rendering XML
5
+ * Add Rubyoshka.component method
6
+ * Remove Modulation dependency
7
+
1
8
  0.4 2019-02-05
2
9
  --------------
3
10
 
data/README.md CHANGED
@@ -226,16 +226,17 @@ greeting.render(name: 'world')
226
226
  ## Templates as components
227
227
 
228
228
  Rubyoshka makes it easy to compose multiple separate templates into a whole HTML
229
- document. Each template can be defined as a self-contained component that can
230
- be reused inside other components. Components should be defined as constants,
231
- either in the global namespace, or on the `Rubyoshka` namespace. Each component
232
- can be defined as either a Rubyoshka instance (using `#H`) or as a `proc` that
233
- returns a Rubyoshka instance:
229
+ document. Each template can be defined as a self-contained component that can be
230
+ reused inside other components. Components can be defined as either a Rubyoshka
231
+ instance (using `#H`), a `proc` that returns a Rubyoshka instance, or using
232
+ `Rubyoshka.component`:
234
233
 
235
234
  ```ruby
235
+ # Simple component relying on global/local context
236
236
  Title = H { h1 title }
237
237
 
238
- # Item is actually a Proc that returns a template
238
+ # Proc component that returns a template
239
+ # Notice how the lambda expression takes keyword arguments
239
240
  Item = ->(id:, text:, checked:) {
240
241
  H {
241
242
  li {
@@ -245,20 +246,29 @@ Item = ->(id:, text:, checked:) {
245
246
  }
246
247
  }
247
248
 
248
- def render_items(items)
249
+ # Components using Rubyoshka.component (or H.component) are a bit more compact.
250
+ # Any parameters are passed as arguments to the block.
251
+ NavBar = Rubyoshka.component do |links|
252
+ div {
253
+ links.each { |l| a l[:title], href: l[:url] }
254
+ }
255
+ end
256
+
257
+ def render_items(items, links)
249
258
  html = H {
250
259
  Title()
260
+ NavBar(links)
251
261
  ul {
252
262
  items.each { |id, attributes|
253
263
  Item id: id, text: attributes[:text], checked: attributes[:active]
254
264
  }
255
265
  }
256
- }.render
266
+ }.render(title: 'Hello from components')
257
267
  end
258
268
  ```
259
269
 
260
270
  Note that a component is invoked as a method, which means that if no arguments
261
- are passed, you should add an empty pair of parens, as shown in the example
271
+ are passed, you must add an empty pair of parens, as shown in the example
262
272
  above.
263
273
 
264
274
  In addition to using components defined as constants, you can also use
@@ -319,8 +329,8 @@ reused in multiple different templates in your app.
319
329
  ### Changing the cache store
320
330
 
321
331
  Rubyoshka ships with a naïve in-memory cache store built-in. You can use
322
- another cache store by overriding the `Rubyoshka.cache_get` and
323
- `Rubyoshka.cache_set` methods (see API [reference](#api-reference)).
332
+ another cache store by overriding the `Rubyoshka.cache` method (see API
333
+ [reference](#rubyoshkacache)).
324
334
 
325
335
  ## Wrapping arbitrary HTML with a component
326
336
 
data/lib/rubyoshka.rb CHANGED
@@ -1,14 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'modulation/gem'
4
3
  require 'escape_utils'
5
4
 
6
- export_default :Rubyoshka
7
-
8
5
  # A Rubyoshka is a template representing a piece of HTML
9
6
  class Rubyoshka
10
- # A Rendering is a rendering of a Rubyoshka
11
- class Rendering
7
+ # A Renderer is a rendering of a Rubyoshka
8
+ class Renderer
12
9
  attr_reader :context
13
10
 
14
11
  # Initializes attributes and renders the given block
@@ -27,8 +24,15 @@ class Rubyoshka
27
24
  @buffer
28
25
  end
29
26
 
30
- E = EscapeUtils
31
-
27
+ def escape_text(text)
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def escape_uri(uri)
32
+ EscapeUtils.escape_uri(v)
33
+ end
34
+
35
+ S_TAG_METHOD_LINE = __LINE__ + 1
32
36
  S_TAG_METHOD = <<~EOF
33
37
  S_TAG_%<TAG>s_PRE = '<%<tag>s'
34
38
  S_TAG_%<TAG>s_CLOSE = '</%<tag>s>'
@@ -46,7 +50,7 @@ class Rubyoshka
46
50
  emit(text)
47
51
  @buffer << S_TAG_%<TAG>s_CLOSE
48
52
  elsif text
49
- @buffer << S_GT << E.escape_html(text.to_s) << S_TAG_%<TAG>s_CLOSE
53
+ @buffer << S_GT << escape_text(text.to_s) << S_TAG_%<TAG>s_CLOSE
50
54
  else
51
55
  @buffer << S_SLASH_GT
52
56
  end
@@ -65,6 +69,7 @@ class Rubyoshka
65
69
  return value if value
66
70
 
67
71
  if sym =~ R_CONST_SYM
72
+ # Component reference (capitalized method name)
68
73
  o = instance_eval(sym.to_s) rescue Rubyoshka.const_get(sym) \
69
74
  rescue Object.const_get(sym)
70
75
  case o
@@ -86,7 +91,8 @@ class Rubyoshka
86
91
  end
87
92
  else
88
93
  tag = sym.to_s
89
- self.class.class_eval(S_TAG_METHOD % { tag: tag, TAG: tag.upcase })
94
+ code = S_TAG_METHOD % { tag: tag, TAG: tag.upcase }
95
+ self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE)
90
96
  send(sym, *args, &block)
91
97
  end
92
98
  end
@@ -101,6 +107,7 @@ class Rubyoshka
101
107
  when Rubyoshka
102
108
  instance_eval(&o.block)
103
109
  when Module
110
+ # If module is given, the component is expected to be a const inside the module
104
111
  emit(o::Component)
105
112
  when nil
106
113
  else
@@ -126,7 +133,7 @@ class Rubyoshka
126
133
  case k
127
134
  when :src, :href
128
135
  @buffer << S_SPACE << k.to_s << S_EQUAL_QUOTE <<
129
- E.escape_uri(v) << S_QUOTE
136
+ EscapeUtils.escape_uri(v) << S_QUOTE
130
137
  else
131
138
  case v
132
139
  when true
@@ -140,7 +147,7 @@ class Rubyoshka
140
147
  }
141
148
  end
142
149
 
143
- # Emits the p tag
150
+ # Emits the p tag (overrides Object#p)
144
151
  # @param text [String] text content of tag
145
152
  # @param props [Hash] tag attributes
146
153
  # @para block [Proc] nested HTML block
@@ -162,7 +169,7 @@ class Rubyoshka
162
169
  # Emits text into the rendering buffer
163
170
  # @param data [String] text
164
171
  def text(data)
165
- @buffer << E.escape_html(data)
172
+ @buffer << escape_text(data)
166
173
  end
167
174
 
168
175
  # Sets a local context for the given block
@@ -195,13 +202,27 @@ class Rubyoshka
195
202
  end
196
203
  end
197
204
 
205
+ class HTMLRenderer < Renderer
206
+ def escape_text(text)
207
+ EscapeUtils.escape_html(text.to_s)
208
+ end
209
+
210
+ end
211
+
212
+ class XMLRenderer < Renderer
213
+ def escape_text(text)
214
+ EscapeUtils.escape_xml(text.to_s)
215
+ end
216
+ end
217
+
198
218
  attr_reader :block
199
219
 
200
220
  # Initializes a Rubyoshka with the given block
201
221
  # @param ctx [Hash] local context
202
222
  # @param block [Proc] nested HTML block
203
223
  # @param [void]
204
- def initialize(**ctx, &block)
224
+ def initialize(mode: :html, **ctx, &block)
225
+ @mode = mode
205
226
  @block = ctx.empty? ? block : proc { with(ctx, &block) }
206
227
  end
207
228
 
@@ -211,7 +232,18 @@ class Rubyoshka
211
232
  # @param context [Hash] context
212
233
  # @return [String]
213
234
  def render(context = H_EMPTY)
214
- Rendering.new(context, &block).to_s
235
+ renderer_class.new(context, &block).to_s
236
+ end
237
+
238
+ def renderer_class
239
+ case @mode
240
+ when :html
241
+ HTMLRenderer
242
+ when :xml
243
+ XMLRenderer
244
+ else
245
+ raise "Invalid mode #{@mode.inspect}"
246
+ end
215
247
  end
216
248
 
217
249
  @@cache = {}
@@ -219,6 +251,10 @@ class Rubyoshka
219
251
  def self.cache
220
252
  @@cache
221
253
  end
254
+
255
+ def self.component(&block)
256
+ proc { |*args| new { instance_exec(*args, &block) } }
257
+ end
222
258
  end
223
259
 
224
260
  module ::Kernel
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Rubyoshka
4
- VERSION = '0.4'
4
+ VERSION = '0.5'
5
5
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyoshka
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-05 00:00:00.000000000 Z
11
+ date: 2021-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: modulation
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '='
18
- - !ruby/object:Gem::Version
19
- version: '0.18'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - '='
25
- - !ruby/object:Gem::Version
26
- version: '0.18'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: escape_utils
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -129,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
115
  - !ruby/object:Gem::Version
130
116
  version: '0'
131
117
  requirements: []
132
- rubygems_version: 3.0.1
118
+ rubygems_version: 3.1.4
133
119
  signing_key:
134
120
  specification_version: 4
135
121
  summary: 'Rubyoshka: composable HTML templating for Ruby'