templet 0.1.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 +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +21 -0
- data/README.md +533 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/templet/component/layout.rb +20 -0
- data/lib/templet/component/partial.rb +32 -0
- data/lib/templet/component.rb +10 -0
- data/lib/templet/html/definition_list.rb +38 -0
- data/lib/templet/html/list.rb +50 -0
- data/lib/templet/html/table.rb +64 -0
- data/lib/templet/html.rb +11 -0
- data/lib/templet/renderer.rb +60 -0
- data/lib/templet/renderers/erb.rb +44 -0
- data/lib/templet/renderers/helpers.rb +16 -0
- data/lib/templet/renderers/list_presenter.rb +22 -0
- data/lib/templet/renderers/tag.rb +86 -0
- data/lib/templet/version.rb +3 -0
- data/lib/templet.rb +21 -0
- data/templet.gemspec +38 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5f53a3264d04846496a5fab85e4870ca1f1028b5
|
4
|
+
data.tar.gz: 35f92da74584cca4bf699f0aff237b96f4772a69
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c5c00ae7fc9c270c20986ec45c9fcfa601dbd64f3cf30ae711ef06192eb86ad4a83e85cf16c3402609b6677ece80db87efe3a68df02284ad0335263f2aacdc84
|
7
|
+
data.tar.gz: 8290792806560547f80b385b7a95ac22003b262e4b23c033a1b130b27a714c8984846bba9546fd65fe8dfb5cc773dadd8f9aef02b77b929f1381841bb2659ca3
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
templet (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
minitest (5.10.2)
|
10
|
+
rake (10.5.0)
|
11
|
+
|
12
|
+
PLATFORMS
|
13
|
+
ruby
|
14
|
+
|
15
|
+
DEPENDENCIES
|
16
|
+
bundler (~> 1.16)
|
17
|
+
minitest (~> 5.0)
|
18
|
+
rake (~> 10.0)
|
19
|
+
templet!
|
20
|
+
|
21
|
+
BUNDLED WITH
|
22
|
+
1.16.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 TODO: Write your name
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,533 @@
|
|
1
|
+
|
2
|
+
# Templet
|
3
|
+
|
4
|
+
## Introduction
|
5
|
+
|
6
|
+
This gem is a stand-alone feather-weight DSL in pure Ruby
|
7
|
+
that renders HTML via method calls.
|
8
|
+
|
9
|
+
It can run from anywhere (within reason), and with next to no set up.
|
10
|
+
Also, it won't cause installation conflicts,
|
11
|
+
as it has no external run-time dependencies.
|
12
|
+
|
13
|
+
For example, it may be used with a framework (like Rails or Sinatra),
|
14
|
+
or as part of a static site generator, or inside a command line script.
|
15
|
+
|
16
|
+
It has three main sections:
|
17
|
+
|
18
|
+
1. A basic (in-line) renderer.
|
19
|
+
|
20
|
+
2. Base classes for splitting up a view into separate components.
|
21
|
+
|
22
|
+
3. Helper methods for rendering HTML tables and lists.
|
23
|
+
|
24
|
+
_Incidentally, and if such a need arises,
|
25
|
+
there is another renderer class, *Templet::Renderers::ERb*,
|
26
|
+
that you may use to insert markup inside of an ERb layout,
|
27
|
+
either on file or as a string._
|
28
|
+
|
29
|
+
## The basic DSL (Renderer)
|
30
|
+
|
31
|
+
The DSL processing (i.e. HTML rendering) is handled by
|
32
|
+
the class, *Templet::Renderer*.
|
33
|
+
But don't expect anything earth-shattering,
|
34
|
+
as this class breaks no new ground.
|
35
|
+
It's as simple a DSL as you're likely to come across.
|
36
|
+
Also, there are a good few others that are similar,
|
37
|
+
e.g. XML Builder, Markaby, Arbre, and Fortitude.
|
38
|
+
|
39
|
+
The DSL allows you to pass in local variables,
|
40
|
+
as well as multiple contexts for method look-ups,
|
41
|
+
which means that the DSL is able to expose a wide range of methods
|
42
|
+
that can be called from the markup code directly.
|
43
|
+
|
44
|
+
However, this basic Renderer, when used by itself,
|
45
|
+
has no in-built functionality for modularity,
|
46
|
+
and so is not really suitable for long HTML pages,
|
47
|
+
or for handling variation, or for code sharing.
|
48
|
+
|
49
|
+
## Components (Layouts and Partials)
|
50
|
+
|
51
|
+
To avoid these limitations, there are, in addition,
|
52
|
+
two base classes supplied that can be used as building blocks
|
53
|
+
for composing view segments.
|
54
|
+
|
55
|
+
They ought to be used in preference to the (above mentioned)
|
56
|
+
*Renderer* class, which they use internally.
|
57
|
+
The *Renderer* provides the context in which these Components are run.
|
58
|
+
|
59
|
+
The two classes, whose API's have just a single *call* method, are:
|
60
|
+
|
61
|
+
1. *Templet::Component::Layout*
|
62
|
+
|
63
|
+
2. *Templet::Component::Partial*
|
64
|
+
|
65
|
+
In most cases they are to be used as superclasses,
|
66
|
+
from which your own custom components (as subclasses) inherit.
|
67
|
+
|
68
|
+
You begin with a single *Layout*, which, typically,
|
69
|
+
contains calls to a number of *Partials*,
|
70
|
+
maybe interspersed with some markup code.
|
71
|
+
|
72
|
+
Using these as base classes,
|
73
|
+
your own subclasses can receive (local) input variables,
|
74
|
+
encapsulate helper methods,
|
75
|
+
and act as a container for constituent elements.
|
76
|
+
|
77
|
+
More specifically,
|
78
|
+
these classes allow you to develop general-purpose components,
|
79
|
+
such as, HTML layouts, Rails forms, Bootstrap menus,
|
80
|
+
and even a full-blown Rails Scaffolding alternative.
|
81
|
+
|
82
|
+
But there's no need for you to embark on such a venture yourself,
|
83
|
+
as these things are implemented in the related gem:
|
84
|
+
[templet\_rails](https://github.com/srycyk/templet_rails).
|
85
|
+
|
86
|
+
## HTML Helpers
|
87
|
+
|
88
|
+
Some further classes are included (in the *templet/html/* sub-directory),
|
89
|
+
that provide a shortened way to render HTML tables and lists.
|
90
|
+
Their content is determined by a Ruby Hash or Array,
|
91
|
+
which is given as input.
|
92
|
+
|
93
|
+
Examples of using these are given towards the end.
|
94
|
+
|
95
|
+
## Renderer Usage
|
96
|
+
|
97
|
+
Except for very small jobs,
|
98
|
+
it's best not to construct an instance of a *Renderer* explicitly,
|
99
|
+
even though this is illustrated in the examples which follow.
|
100
|
+
|
101
|
+
As noted, it's neater to use the *Renderer* implicitly,
|
102
|
+
that is, by means of a *Layout* containing a number of *Partials*.
|
103
|
+
|
104
|
+
Still, it is useful to have a grounding in the basic rules and techniques,
|
105
|
+
as they apply to the Components as well.
|
106
|
+
|
107
|
+
### Rudimentary Renderer Usage
|
108
|
+
|
109
|
+
No need to begin by reading an API,
|
110
|
+
_(anyway, there isn't one - but most classes just have a **call** method),_
|
111
|
+
as this example shows elementary usage:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
require 'templet/renderer'
|
115
|
+
|
116
|
+
message = 'Hello there'
|
117
|
+
|
118
|
+
html = Templet::Renderer.new.call do
|
119
|
+
header = head { title 'Role' }
|
120
|
+
|
121
|
+
# +message+ is the closure variable above
|
122
|
+
content = p { message }
|
123
|
+
|
124
|
+
# The Renderer only shows what a block returns
|
125
|
+
# which should be a string, or a callable that returns a string
|
126
|
+
# To return multiple values, use an array of such
|
127
|
+
html { [ header, body(content) ] }
|
128
|
+
end
|
129
|
+
|
130
|
+
puts html
|
131
|
+
```
|
132
|
+
|
133
|
+
This produces the following HTML:
|
134
|
+
|
135
|
+
```html
|
136
|
+
<html><head><title>Role</title>
|
137
|
+
</head>
|
138
|
+
|
139
|
+
<body><p>Hello there</p>
|
140
|
+
</body>
|
141
|
+
</html>
|
142
|
+
```
|
143
|
+
|
144
|
+
> Note that the code blocks (passed to the *Renderer*)
|
145
|
+
> are not run in the lexical context that blocks normally are.
|
146
|
+
> The blocks are actually executed inside of an instance of *Renderer*
|
147
|
+
> which inherits from *BasicObject* -
|
148
|
+
> which is a threadbare class of very few methods.
|
149
|
+
> It's up to you to provide the lookup context(s),
|
150
|
+
> which are passed into the *Renderer's* constructor.
|
151
|
+
|
152
|
+
### More Advanced Renderer Usage
|
153
|
+
|
154
|
+
The following example explains more
|
155
|
+
and covers a lot to do with visibility and scoping:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
require 'templet'
|
159
|
+
|
160
|
+
class Lister
|
161
|
+
def items
|
162
|
+
%w(One Two Three)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def content
|
167
|
+
'Some content'
|
168
|
+
end
|
169
|
+
|
170
|
+
col_tag = Templet::Renderers::Tag.new(:div, class: :col_md_4)
|
171
|
+
|
172
|
+
# The first two arguments are contexts for method lookups
|
173
|
+
#
|
174
|
+
# The final argument list local variables which take precendence
|
175
|
+
#
|
176
|
+
# The block renders the markup
|
177
|
+
# Note the shortcut call, this call is stated in full in the above example
|
178
|
+
html = Templet.(self, Lister.new, title: 'A Title') do
|
179
|
+
more_content = 'More content'
|
180
|
+
|
181
|
+
# +title+ is (in effect) a local variable passed into the constru
|
182
|
+
ctor
|
183
|
+
[ -> { h1(title, :strong) }, # you can include anything callable
|
184
|
+
|
185
|
+
# Calls +items+ from Lister instance, given as a contructor arg
|
186
|
+
ument
|
187
|
+
# The +_p+ call renders a <p> tag
|
188
|
+
# without the underscore the Kernel#p method would override
|
189
|
+
_p(ul(:list_unstyled) { items.map {|item| li item } }),
|
190
|
+
|
191
|
+
div(:row) do
|
192
|
+
# Calls +content+ because +self+ is passed into the contructo
|
193
|
+
r
|
194
|
+
# +col_tag+ is a closure variable defined above
|
195
|
+
[ col_tag.(content), col_tag.(more_content), col_tag.('...')
|
196
|
+
]
|
197
|
+
end
|
198
|
+
]
|
199
|
+
end
|
200
|
+
|
201
|
+
puts html
|
202
|
+
```
|
203
|
+
|
204
|
+
This produces the following HTML:
|
205
|
+
|
206
|
+
```html
|
207
|
+
<h1 class='strong'>A Title</h1>
|
208
|
+
|
209
|
+
<p><ul class='list-unstyled'><li>One</li>
|
210
|
+
|
211
|
+
<li>Two</li>
|
212
|
+
|
213
|
+
<li>Three</li>
|
214
|
+
</ul>
|
215
|
+
</p>
|
216
|
+
|
217
|
+
<div class='row'><div class='col-md-4'>Some content</div>
|
218
|
+
|
219
|
+
<div class='col-md-4'>More content</div>
|
220
|
+
|
221
|
+
<div class='col-md-4'>...</div>
|
222
|
+
</div>
|
223
|
+
```
|
224
|
+
|
225
|
+
## Notes on Usage
|
226
|
+
|
227
|
+
The main quirk is that the *Renderer* only outputs
|
228
|
+
the actual return value of a given block.
|
229
|
+
That is, statements preceding the very last one won't
|
230
|
+
show up in the resultant markup.
|
231
|
+
*This behaviour differs from that of most other markup API's.*
|
232
|
+
|
233
|
+
A block's return type must be either an array of strings or of *callable*
|
234
|
+
entities (which themselves return one or more strings).
|
235
|
+
This array can be nested at any depth.
|
236
|
+
|
237
|
+
Importantly, the block, passed to *Renderer#call*, is **not**
|
238
|
+
executed in its natural local (i.e. lexical) scope.
|
239
|
+
This means that, although local variables will be accessible,
|
240
|
+
the methods (within the current context) won't - unless the
|
241
|
+
current value of *self* is passed into the *Renderer's* constructor,
|
242
|
+
as one of the initial arguments.
|
243
|
+
|
244
|
+
*To put this in more practical terms: be aware that if an error does occur,
|
245
|
+
its origin may be flagrantly misreported in the stack trace.*
|
246
|
+
|
247
|
+
The tests have more examples of usage,
|
248
|
+
also, the source code is easy to follow and is commented.
|
249
|
+
|
250
|
+
But don't dig too deep.
|
251
|
+
There's not a lot you need to learn to get started,
|
252
|
+
and you should be able to pick up the rest as you go along.
|
253
|
+
|
254
|
+
## Components
|
255
|
+
|
256
|
+
As said, Components facilitate a modular (object oriented) approach
|
257
|
+
to rendering markup.
|
258
|
+
|
259
|
+
You begin with a Layout, which, typically, contains a number of Partials.
|
260
|
+
|
261
|
+
There's no need to have more than a single Layout,
|
262
|
+
since Partials can be nested inside one another.
|
263
|
+
|
264
|
+
Together, they perform much the same function as their namesakes in Rails.
|
265
|
+
|
266
|
+
### Examples of a Layout with Partials
|
267
|
+
|
268
|
+
#### A Very Basic Layout Example
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
require 'templet/component'
|
272
|
+
|
273
|
+
html = Templet::Component::Layout.new(heading: 'A Title').call do
|
274
|
+
# The method calls become HTML tags
|
275
|
+
html do
|
276
|
+
# +heading+ is passed by name above, it overrides
|
277
|
+
[ head(title heading), body { div 'Hello' } ]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
puts html
|
282
|
+
```
|
283
|
+
|
284
|
+
This produces the following HTML:
|
285
|
+
|
286
|
+
```html
|
287
|
+
<html><head><title>A Title</title>
|
288
|
+
</head>
|
289
|
+
|
290
|
+
<body><div>Hello</div>
|
291
|
+
</body>
|
292
|
+
</html>
|
293
|
+
```
|
294
|
+
|
295
|
+
#### A Slightly More Realistic Example
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
require 'templet/component'
|
299
|
+
|
300
|
+
class HtmlLayout < Templet::Component::Layout
|
301
|
+
def call
|
302
|
+
super do
|
303
|
+
html do
|
304
|
+
[ head { title heading },
|
305
|
+
# The renderer is passed to calling block
|
306
|
+
body(yield renderer) ]
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class BodyPart < Templet::Component::Partial
|
313
|
+
def call
|
314
|
+
super do
|
315
|
+
span hello
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
private
|
320
|
+
|
321
|
+
def hello
|
322
|
+
'Hello'
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
class BodyBuild < Templet::Component::Partial
|
327
|
+
def call
|
328
|
+
# This is an alternative way to render markup, i.e. without a super call
|
329
|
+
renderer.call { div BodyPart.new(renderer), :row }
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
html = HtmlLayout.new(heading: 'Down').call do |renderer|
|
334
|
+
# No need to explicitly call(), this'll be done later on
|
335
|
+
BodyBuild.new(renderer)
|
336
|
+
end
|
337
|
+
|
338
|
+
puts html
|
339
|
+
```
|
340
|
+
|
341
|
+
This produces the following HTML:
|
342
|
+
|
343
|
+
```html
|
344
|
+
<html><head><title>Down</title>
|
345
|
+
</head>
|
346
|
+
|
347
|
+
<body><div class='row'><span>Hello</span>
|
348
|
+
</div>
|
349
|
+
</body>
|
350
|
+
</html>
|
351
|
+
```
|
352
|
+
|
353
|
+
> Although this DSL relies heavily on *method_missing*,
|
354
|
+
> this has not brought poor performance - quite the reverse.
|
355
|
+
> After all, this DSL is tiny, and thus quick to load and run,
|
356
|
+
> making no calls to external libraries.
|
357
|
+
> In ERb, or HAML, the source code is parsed (byte by byte)
|
358
|
+
> so as to generate some new Ruby code, that is finally executed.
|
359
|
+
|
360
|
+
## Examples of Rendering HTML Composites
|
361
|
+
|
362
|
+
In these examples, a *nil* value is passed to the constructor,
|
363
|
+
but in application code, this will be, in nearly all cases,
|
364
|
+
replaced by an instance of a *Renderer*.
|
365
|
+
|
366
|
+
> To load these claases you must add: `require 'templet/html'`.
|
367
|
+
|
368
|
+
### An Unordered List
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
Templet::Html::List.new(nil).(["One", "Two", "Three"])
|
372
|
+
```
|
373
|
+
|
374
|
+
This produces the following HTML:
|
375
|
+
|
376
|
+
```html
|
377
|
+
<ul><li>One</li>
|
378
|
+
|
379
|
+
<li>Two</li>
|
380
|
+
|
381
|
+
<li>Three</li>
|
382
|
+
</ul>
|
383
|
+
```
|
384
|
+
|
385
|
+
### A Definition List
|
386
|
+
|
387
|
+
In basic cases, you pass in a Hash,
|
388
|
+
where the key is the title (the *dt* tag),
|
389
|
+
and the value is the data (the *dd* tag).
|
390
|
+
This is done as follows:
|
391
|
+
|
392
|
+
```ruby
|
393
|
+
Templet::Html::DefinitionList.new(nil).({"One"=>"First", "Two"=>"Second", "Three"=>"Third"})
|
394
|
+
```
|
395
|
+
|
396
|
+
This produces the following HTML:
|
397
|
+
|
398
|
+
```html
|
399
|
+
<dl><dt>One</dt>
|
400
|
+
<dd>First</dd>
|
401
|
+
|
402
|
+
<dt>Two</dt>
|
403
|
+
<dd>Second</dd>
|
404
|
+
|
405
|
+
<dt>Three</dt>
|
406
|
+
<dd>Third</dd>
|
407
|
+
</dl>
|
408
|
+
```
|
409
|
+
|
410
|
+
In addition, the value of an entry in this *control* Hash
|
411
|
+
can also be a Symbol or Proc.
|
412
|
+
In these cases you also supply a record, as a second parameter to *call*.
|
413
|
+
If a Symbol is given then it's used as a (Hash) key,
|
414
|
+
as in `record[key]`.
|
415
|
+
If a Proc is given then it's called with the
|
416
|
+
record passed as the first parameter, as in `func.call(record)`.
|
417
|
+
|
418
|
+
```ruby
|
419
|
+
record = OpenStruct.new(field_1: 'Value 1', field_2: 'Value 2')
|
420
|
+
|
421
|
+
controls = { first: :field_1, second: -> (record) { record.send(:field_2) } }
|
422
|
+
|
423
|
+
Templet::Html::DefinitionList.new(nil).(controls, record, html_class: 'low')
|
424
|
+
```
|
425
|
+
|
426
|
+
This produces the following HTML:
|
427
|
+
|
428
|
+
```html
|
429
|
+
<dl class='low'><dt>First</dt>
|
430
|
+
<dd>Value 1</dd>
|
431
|
+
|
432
|
+
<dt>Second</dt>
|
433
|
+
<dd>Value 2</dd>
|
434
|
+
</dl>
|
435
|
+
```
|
436
|
+
|
437
|
+
### A Table
|
438
|
+
|
439
|
+
To render an HTML table you pass to the *call* method,
|
440
|
+
a control Hash (as set out just above),
|
441
|
+
and a list of records, obviously, with a table row for each record.
|
442
|
+
|
443
|
+
```ruby
|
444
|
+
controls = { 'Title 1' => nil, # shows the whole of the 'numbers' hash
|
445
|
+
# if an array was given, it'd be indexed
|
446
|
+
'Title 2' => 'Two', # shows the 'numbers' hash entry 'Two'
|
447
|
+
# calls this proc - the first param is a Renderer instance
|
448
|
+
'Title 3' => proc {|_, numbers| numbers['Three'] }
|
449
|
+
}
|
450
|
+
|
451
|
+
Templet::Html::Table.new(nil).(controls, [{"One"=>"First", "Two"=>"Second", "Three"=>"Third"}])
|
452
|
+
```
|
453
|
+
|
454
|
+
This produces the following HTML:
|
455
|
+
|
456
|
+
```html
|
457
|
+
<table><thead><tr><th>Title 1</th>
|
458
|
+
|
459
|
+
<th>Title 2</th>
|
460
|
+
|
461
|
+
<th>Title 3</th>
|
462
|
+
</tr>
|
463
|
+
</thead>
|
464
|
+
|
465
|
+
<tbody><tr>{"One"=>"First", "Two"=>"Second", "Three"=>"Third"}
|
466
|
+
<td>Second</td>
|
467
|
+
|
468
|
+
<td>Third</td>
|
469
|
+
</tr>
|
470
|
+
</tbody>
|
471
|
+
|
472
|
+
<tfoot><tr><td colspan='3'></td>
|
473
|
+
</tr>
|
474
|
+
</tfoot>
|
475
|
+
</table>
|
476
|
+
```
|
477
|
+
|
478
|
+
## Examples of Rendering Tags
|
479
|
+
|
480
|
+
As mentioned, the *Renderer* class,
|
481
|
+
(via a block passed to its *call* method),
|
482
|
+
lets you render markup by direct Ruby method calls.
|
483
|
+
|
484
|
+
Here are a few examples of some of the ways of using the API to render tags:
|
485
|
+
|
486
|
+
* `span('Hello', :small, id: '999') => <span id='999' class='small'>Hello</span>`
|
487
|
+
|
488
|
+
* `__p(:pull_right) { 'Hello' } => <p class='pull-right'>Hello</p>`
|
489
|
+
|
490
|
+
* `div('', :pull_right, class: 'clearfix') => <div class='clearfix pull-right'></div>`
|
491
|
+
|
492
|
+
As you can see, an HTML class can be given as an argument.
|
493
|
+
Any underscores, in the class name, will be replaced
|
494
|
+
by dashes in the (generated) markup.
|
495
|
+
|
496
|
+
To avoid method name clashes, you can prefix a method call with a number of
|
497
|
+
underscores, and these won't appear in the corresponding tag name.
|
498
|
+
For example, this is particularly important when rendering the HTML tag *p*,
|
499
|
+
as there's a Ruby *Kernel* method called *p*, that may be called first.
|
500
|
+
|
501
|
+
If you prefer, you can call a *tag* helper method instead of
|
502
|
+
inferring a tag name from a method name. For example:
|
503
|
+
|
504
|
+
* `tag(:p, 'Hello', :pull_right) => <p class='pull-right'>Hello</p>`
|
505
|
+
|
506
|
+
Note that this method will mask any other method,
|
507
|
+
of the same name (i.e. *tag*), higher up in the inheritance hierarchy.
|
508
|
+
|
509
|
+
## Installation
|
510
|
+
|
511
|
+
Add this line to your application's Gemfile:
|
512
|
+
|
513
|
+
```ruby
|
514
|
+
gem 'templet'
|
515
|
+
```
|
516
|
+
|
517
|
+
And then execute:
|
518
|
+
|
519
|
+
```
|
520
|
+
$ bundle
|
521
|
+
```
|
522
|
+
|
523
|
+
Or install it yourself as:
|
524
|
+
|
525
|
+
```
|
526
|
+
$ gem install templet
|
527
|
+
```
|
528
|
+
|
529
|
+
## Licence
|
530
|
+
|
531
|
+
The gem is available as open source under the terms
|
532
|
+
of the [MIT License](https://opensource.org/licenses/MIT).
|
533
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "templet"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module Templet
|
3
|
+
module Component
|
4
|
+
# For composing views - the first step
|
5
|
+
class Layout < Partial
|
6
|
+
# +contexts+:: A list containing objects whose methods will be looked up
|
7
|
+
# +locals+:: Objects you can reference by the given name
|
8
|
+
def initialize(*contexts, **locals)
|
9
|
+
contexts = [ self, *contexts ]
|
10
|
+
|
11
|
+
self.renderer = Renderer.new(*contexts, **locals)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.call(*contexts, **locals, &block)
|
15
|
+
new(*contexts, **locals).(&block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module Templet
|
3
|
+
module Component
|
4
|
+
# Used for composing views, either within a Layout or another Parial
|
5
|
+
class Partial
|
6
|
+
attr_accessor :renderer
|
7
|
+
|
8
|
+
# +contexts+:: A list containing objects whose methods will be looked up
|
9
|
+
# +locals+:: Objects you can reference by the name given as the key
|
10
|
+
def initialize(renderer, *contexts, **locals)
|
11
|
+
self.renderer = renderer&.new_instance(self, *contexts, **locals) ||
|
12
|
+
Renderer.new(self, *contexts, **locals)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Entry point - the block returns markup
|
16
|
+
def call(&block)
|
17
|
+
renderer.(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Shortcut
|
21
|
+
def self.call(renderer, *contexts, **locals, &block)
|
22
|
+
new(renderer, *contexts, **locals).(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# If +call+ gets overriden then use +compose+ instead
|
28
|
+
alias compose call
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
require 'templet/component/partial'
|
3
|
+
|
4
|
+
module Templet
|
5
|
+
module Html
|
6
|
+
# Renders an HTML dl from a Hash
|
7
|
+
class DefinitionList < Component::Partial
|
8
|
+
# +controls+ [Hash]
|
9
|
+
# The key is the field's title
|
10
|
+
# The value is the field value || a Proc which calls the record's method
|
11
|
+
def call(controls, record=nil, html_class: nil)
|
12
|
+
super() do
|
13
|
+
dl(html_class || default_html_class) do
|
14
|
+
controls.to_h.map do |title, data|
|
15
|
+
title = title.to_s.capitalize.tr('_', ' ')
|
16
|
+
|
17
|
+
if data.respond_to?(:call)
|
18
|
+
data = data.(record)
|
19
|
+
elsif Symbol === data
|
20
|
+
data = if record and record.respond_to?(:[])
|
21
|
+
record[data]
|
22
|
+
else
|
23
|
+
data.to_s.capitalize.tr('_', ' ')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
dt(title) + dd(data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_html_class
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
require 'templet/component/partial'
|
3
|
+
|
4
|
+
module Templet
|
5
|
+
module Html
|
6
|
+
class List < Component::Partial
|
7
|
+
def call(*items, html_class: nil,
|
8
|
+
item_class: nil,
|
9
|
+
selection: nil,
|
10
|
+
selected_class: 'active')
|
11
|
+
super() do
|
12
|
+
ul html_class do
|
13
|
+
items.flatten.map.with_index do |item, index|
|
14
|
+
li item, li_class(selection, item, index,
|
15
|
+
item_class, selected_class)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def selected?(selection, item, index)
|
24
|
+
case selection
|
25
|
+
when nil, false
|
26
|
+
false
|
27
|
+
when Integer
|
28
|
+
index == selection
|
29
|
+
when Regexp
|
30
|
+
selection === item
|
31
|
+
else
|
32
|
+
selection.to_s == item.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def li_class(selection, item, index, item_class, selected_class)
|
37
|
+
if selected?(selection, item, index)
|
38
|
+
if item_class and not item_class.empty?
|
39
|
+
"#{item_class} #{selected_class}"
|
40
|
+
else
|
41
|
+
selected_class
|
42
|
+
end
|
43
|
+
else
|
44
|
+
item_class
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
require 'templet/component/partial'
|
3
|
+
|
4
|
+
module Templet
|
5
|
+
module Html
|
6
|
+
# Renders an HTML table from a Hash
|
7
|
+
class Table < Component::Partial
|
8
|
+
# +controls+ [Hash]
|
9
|
+
# The key is a Proc || a field name (if it begins with _ it's not shown)
|
10
|
+
# The value is a Proc || an index || nil (for a single column table)
|
11
|
+
def call(controls, records, opaque_heading: nil, opaque_row: nil,
|
12
|
+
html_class: nil, footer: '')
|
13
|
+
controls = controls.to_h
|
14
|
+
|
15
|
+
super() do
|
16
|
+
_table(html_class || default_html_class) do
|
17
|
+
[ thead do
|
18
|
+
tr do
|
19
|
+
controls.keys.map do |title|
|
20
|
+
if title.respond_to?(:call)
|
21
|
+
th title.(self, opaque_heading, opaque_row)
|
22
|
+
else
|
23
|
+
th heading(title)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end,
|
28
|
+
|
29
|
+
tbody do
|
30
|
+
records.map do |record|
|
31
|
+
tr do
|
32
|
+
controls.values.map.with_index do |value, index|
|
33
|
+
if value.respond_to?(:call)
|
34
|
+
td value.(self, record, opaque_row)
|
35
|
+
elsif value
|
36
|
+
td record[value]
|
37
|
+
else
|
38
|
+
Array === record ? record[index] : record
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end,
|
44
|
+
|
45
|
+
tfoot do
|
46
|
+
tr do
|
47
|
+
td(colspan: controls.size) { footer }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_html_class
|
56
|
+
end
|
57
|
+
|
58
|
+
def heading(title)
|
59
|
+
title[0] == '_' ? '' : title.capitalize
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
data/lib/templet/html.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
require "ostruct"
|
3
|
+
|
4
|
+
require "templet/renderers/helpers"
|
5
|
+
require "templet/renderers/list_presenter"
|
6
|
+
require "templet/renderers/tag"
|
7
|
+
|
8
|
+
module Templet
|
9
|
+
# Performs the rendition
|
10
|
+
class Renderer < BasicObject
|
11
|
+
include Renderers::Helpers
|
12
|
+
|
13
|
+
# +contexts+ a list of object refererences for method lookups
|
14
|
+
#
|
15
|
+
# +locals+ named variables passed into the renderer
|
16
|
+
def initialize(*contexts, **locals)
|
17
|
+
@contexts = contexts.flatten
|
18
|
+
|
19
|
+
# Local variables take precedence
|
20
|
+
@contexts.unshift ::OpenStruct.new(**locals) if locals.any?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Used for augmenting and overriding method lookups in children
|
24
|
+
def new_instance(*contexts, **locals)
|
25
|
+
Renderer.new(*(contexts | @contexts), **locals)
|
26
|
+
end
|
27
|
+
|
28
|
+
# The block contains the markup
|
29
|
+
def call(&block)
|
30
|
+
Renderers::ListPresenter.new.(instance_eval &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(name, *args, &block)
|
34
|
+
@contexts.each do |context|
|
35
|
+
if context.respond_to?(name, true)
|
36
|
+
return context.send(name, *args, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
fallback(name, *args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def respond_to?(method_name, *)
|
43
|
+
@contexts.each do |context|
|
44
|
+
return true if context.respond_to?(method_name, true)
|
45
|
+
end
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def tag(name, *args, &block)
|
52
|
+
Renderers::Tag.new(name).(*args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Allows you to reimplement +fallback+ in a subclass
|
56
|
+
# For example, you might use the Rails helper method +content_tag+ instead
|
57
|
+
alias fallback tag
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
require 'erb'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Templet
|
6
|
+
module Renderers
|
7
|
+
# For rendering a supplied block within an ERb template
|
8
|
+
class ERb
|
9
|
+
attr_accessor :erb, :context
|
10
|
+
|
11
|
+
# template_path can be a local ERb file, or template text
|
12
|
+
#
|
13
|
+
# locals are local variables for the ERb template alone
|
14
|
+
def initialize(template, **locals)
|
15
|
+
self.erb = ERB.new get_template(template)
|
16
|
+
|
17
|
+
self.context = OpenStruct.new(**locals)
|
18
|
+
end
|
19
|
+
|
20
|
+
# The return value from the block in substituted in <%= yield %>
|
21
|
+
def call(&block)
|
22
|
+
locals_binding = context.instance_eval { binding }
|
23
|
+
|
24
|
+
erb.result locals_binding, &block
|
25
|
+
end
|
26
|
+
|
27
|
+
# Shortcut to instance method
|
28
|
+
def self.call(template_path, **locals, &block)
|
29
|
+
new(template_path, **locals).(&block)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def get_template(template)
|
35
|
+
if template =~ /<%/
|
36
|
+
template
|
37
|
+
else
|
38
|
+
IO.read template
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
module Templet
|
3
|
+
module Renderers
|
4
|
+
# Converts lists of strings and/or callable objects into a multiline string
|
5
|
+
class ListPresenter
|
6
|
+
def call(*elements)
|
7
|
+
elements.flatten.compact.map do |element|
|
8
|
+
element = recall(element)
|
9
|
+
|
10
|
+
Array === element ? call(*element) : element.to_s
|
11
|
+
end * EOL
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def recall(element)
|
17
|
+
element.respond_to?(:call) ? recall(element.call) : element
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
require "templet/renderers/list_presenter"
|
3
|
+
|
4
|
+
module Templet
|
5
|
+
module Renderers
|
6
|
+
# Renders an XML tag
|
7
|
+
class Tag < Struct.new(:tag_name, :default_atts)
|
8
|
+
@@level = 0
|
9
|
+
|
10
|
+
# A shortcut for calling directly.
|
11
|
+
def self.call(*args, &block)
|
12
|
+
new(args.shift).(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
# +args+:: The first element becomes the tag's name.
|
16
|
+
#
|
17
|
+
# +args+:: The remaining elements are the tag's body and/or HTML class.
|
18
|
+
#
|
19
|
+
# +atts+:: An optional final (Hash) argument are rendered as the tag's attributes.
|
20
|
+
#
|
21
|
+
# If a block is given:
|
22
|
+
# The tag's body is what the block returns
|
23
|
+
# If there's an argument (String Symbol) then it's added to the tag's HTML class.
|
24
|
+
#
|
25
|
+
# If NO block is given:
|
26
|
+
# The tag's body is the first argument.
|
27
|
+
# If there's a second (String Symbol) argument it's added to the tag's HTML class.
|
28
|
+
#
|
29
|
+
# Note that in attribute (and tag) names underscores are replaced
|
30
|
+
# with dashes.
|
31
|
+
def call(*args, **atts)
|
32
|
+
content, html_class = block_given? ? [ yield, args.first ] : args
|
33
|
+
|
34
|
+
attributes = set_html_class all_atts(atts), html_class
|
35
|
+
|
36
|
+
render tag_name, content, attributes
|
37
|
+
end
|
38
|
+
|
39
|
+
alias to_s call
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def render(name, content, **atts)
|
44
|
+
name = dashit name.to_s.sub(/^_+/, '')
|
45
|
+
|
46
|
+
content = ListPresenter.new.(content)
|
47
|
+
|
48
|
+
"<#{name}#{atts_to_s atts}>#{content}</#{name}>#{EOL}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Change underscores to dashes when specifying
|
52
|
+
# XML tag names, attribute names and html classes.
|
53
|
+
# For a single underscore, put in two.
|
54
|
+
def dashit(name)
|
55
|
+
(name || '').to_s.tr('_', '-').gsub(/--/, '_') # could be better!
|
56
|
+
end
|
57
|
+
|
58
|
+
def dash_symbol(value)
|
59
|
+
Symbol === value ? dashit(value) : value
|
60
|
+
end
|
61
|
+
|
62
|
+
def atts_to_s(atts)
|
63
|
+
atts.reduce '' do |acc, (key, value)|
|
64
|
+
acc << " #{dashit key}='#{dash_symbol value}'"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def all_atts(atts)
|
69
|
+
(default_atts || {}).merge atts
|
70
|
+
end
|
71
|
+
|
72
|
+
# If there's already an HTML class then append to it
|
73
|
+
def set_html_class(atts, html_class)
|
74
|
+
unless (new_html_class = dashit(html_class)).empty?
|
75
|
+
atts[:class] = existing_html_class(atts) << new_html_class
|
76
|
+
end
|
77
|
+
atts
|
78
|
+
end
|
79
|
+
|
80
|
+
def existing_html_class(atts)
|
81
|
+
atts.key?(:class) ? "#{dash_symbol atts[:class]} " : ''
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
data/lib/templet.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require "templet/version"
|
3
|
+
require "templet/renderer"
|
4
|
+
require "templet/renderers/erb"
|
5
|
+
|
6
|
+
require "templet/component"
|
7
|
+
require "templet/html"
|
8
|
+
|
9
|
+
module Templet
|
10
|
+
EOL = "\n"
|
11
|
+
|
12
|
+
def self.call(*contexts, &block)
|
13
|
+
renderer = Renderer.new(*contexts)
|
14
|
+
|
15
|
+
block ? renderer.(&block) : renderer
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.erb(template_path, **locals, &block)
|
19
|
+
Renderers::Erb.(template_path, **locals, &block)
|
20
|
+
end
|
21
|
+
end
|
data/templet.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "templet/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "templet"
|
8
|
+
spec.version = Templet::VERSION
|
9
|
+
spec.authors = ["stephen"]
|
10
|
+
spec.email = ["stephen@googlemail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{DSL to render XML/HTML}
|
13
|
+
spec.description = %q{Generates HTML tags from pure Ruby, using a method name as a tag's name, via method_missing. Also renders HTML components.}
|
14
|
+
spec.homepage = "https://github.com/srycyk/templet"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
=begin
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
22
|
+
else
|
23
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
24
|
+
"public gem pushes."
|
25
|
+
end
|
26
|
+
=end
|
27
|
+
|
28
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
29
|
+
f.match(%r{^(test|spec|features)/})
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
36
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
37
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: templet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- stephen
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-11-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
description: Generates HTML tags from pure Ruby, using a method name as a tag's name,
|
56
|
+
via method_missing. Also renders HTML components.
|
57
|
+
email:
|
58
|
+
- stephen@googlemail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- Gemfile.lock
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- lib/templet.rb
|
73
|
+
- lib/templet/component.rb
|
74
|
+
- lib/templet/component/layout.rb
|
75
|
+
- lib/templet/component/partial.rb
|
76
|
+
- lib/templet/html.rb
|
77
|
+
- lib/templet/html/definition_list.rb
|
78
|
+
- lib/templet/html/list.rb
|
79
|
+
- lib/templet/html/table.rb
|
80
|
+
- lib/templet/renderer.rb
|
81
|
+
- lib/templet/renderers/erb.rb
|
82
|
+
- lib/templet/renderers/helpers.rb
|
83
|
+
- lib/templet/renderers/list_presenter.rb
|
84
|
+
- lib/templet/renderers/tag.rb
|
85
|
+
- lib/templet/version.rb
|
86
|
+
- templet.gemspec
|
87
|
+
homepage: https://github.com/srycyk/templet
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.6.12
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: DSL to render XML/HTML
|
111
|
+
test_files: []
|