demeler 1.0.0 → 1.0.1
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/.gitignore +2 -0
- data/CHANGELOG.md +11 -1
- data/README.md +262 -67
- data/lib/demeler.rb +33 -22
- data/lib/demeler/version.rb +1 -1
- data/notes +33 -3
- data/spec/demeler.rb +14 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0c386f96ecc1bd387757913d8c06df79c31a705
|
4
|
+
data.tar.gz: bed41140c85456d8d829e8b9919bbc70b9a7d838
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a75c02f4294c9da6b8fe6159c274c05a793c2ce2a31c90815f677723082b12d1117c0366543cc0fb08878442510d1d348af1520d3a344ec8aed1b53941109aa
|
7
|
+
data.tar.gz: c6eff11ee04f5a3b2f95f5938b5ed3f3ade2de6b158141bb3ce79f7683b2b38a738888fb7264f92ebdee7d0ac01713ac08f88645b81dddcddc7970cb696e23ed
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,2 +1,12 @@
|
|
1
|
+
# 1.0.1
|
2
|
+
* Changed the `clear` method to return self so that clear can be chained.
|
3
|
+
* Corrected some of the comments above individual methods.
|
4
|
+
* Made some corrections and additions to the README.
|
5
|
+
* Made `write_html` a private method because it's only used by `to_html`.
|
6
|
+
* Added an argument to `build` and `initialize` to allow a session variable to be passed through.
|
7
|
+
* Corrected a problem with the `select` control in that the attributes were not being applied.
|
8
|
+
* Added a variable to `build` and `initialize` to be able to pass through a user argument. I called it `session` because that's what it would commonly be used for, but you could pass anything and access it in your Demeler code. For example, if you needed session _and_ some other variables, you would just pass them all in a Hash, including session.
|
9
|
+
|
10
|
+
|
1
11
|
# 1.0.0
|
2
|
-
* Initial version.
|
12
|
+
* Initial version.
|
data/README.md
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
# Demeler Gem
|
2
2
|
|
3
|
-
|
3
|
+
**Copyright (c) 2017 Michael J Welch, Ph.D. <mjwelchphd@gmail.com>**
|
4
|
+
|
5
|
+
_NOTE: I appologize that the documentation isn't better than it is, but I'm running way behind in my work trying to make this into a gem in order to preserve and share it._
|
6
|
+
|
4
7
|
All files in this distribution are subject to the terms of the MIT license.
|
5
8
|
|
6
|
-
This gem builds HTML code on-the-fly. The advantages are:
|
9
|
+
This gem builds HTML code on-the-fly. The advantages are:
|
10
|
+
|
11
|
+
1. HTML code is properly formed with respect to tags and nesting;
|
12
|
+
2. the code is dynamic, i.e., values from an object containing data (if used) are automatically extracted and inserted into the resultant HTML code; and
|
13
|
+
3. if there are errors, the error message is generated also.
|
7
14
|
|
8
15
|
The French word démêler means "to unravel," and that's sort of what this gem does. Démêler is pronounced "day-meh-lay." It unravels your inputs to form HTML code. The diacritical marks are not used in the name for compatibility.
|
9
16
|
|
@@ -12,8 +19,8 @@ This class doesn't depend on any particular framework, but I use it with Ruby Se
|
|
12
19
|
|
13
20
|
## The Demeler gem generates HTML from three inputs:
|
14
21
|
* A Ruby source file you write;
|
15
|
-
* A Hash-based object you provide, like Sequel::Model objects
|
16
|
-
* An errors list inside the Hash-based object
|
22
|
+
* A Hash-based object you provide, like Sequel::Model objects; and
|
23
|
+
* An errors list inside the Hash-based object.
|
17
24
|
|
18
25
|
Let's start with the most basic form, a simple example. Run `irb` and enter this:
|
19
26
|
|
@@ -187,7 +194,7 @@ Any attribute can be added in this way.
|
|
187
194
|
|
188
195
|
## Embedding text between tags on one line
|
189
196
|
|
190
|
-
Normally, anything in brackets {} is embedded like this
|
197
|
+
Normally, anything in brackets {} is embedded like this; `p{"Some text."}` yields:
|
191
198
|
|
192
199
|
```html
|
193
200
|
<!-- begin generated output -->
|
@@ -197,7 +204,7 @@ Normally, anything in brackets {} is embedded like this: `p{"Some text."}` yield
|
|
197
204
|
<!-- end generated output -->
|
198
205
|
```
|
199
206
|
|
200
|
-
You can make it come out on one line by using the
|
207
|
+
You can make it come out on one line by using the `:text` attribute; `p :text=>"Some text."` yields:
|
201
208
|
|
202
209
|
```html
|
203
210
|
<!-- begin generated output -->
|
@@ -205,7 +212,7 @@ You can make it come out on one line by using the :text attribute: `p :text=>"So
|
|
205
212
|
<!-- end generated output -->
|
206
213
|
```
|
207
214
|
|
208
|
-
In most cases, this can be achieved just by eliminating the {}
|
215
|
+
In most cases, this can be achieved just by eliminating the {}; `p "Some text." yields:
|
209
216
|
|
210
217
|
```html
|
211
218
|
<!-- begin generated output -->
|
@@ -215,101 +222,289 @@ In most cases, this can be achieved just by eliminating the {}: `p "Some text."
|
|
215
222
|
|
216
223
|
This is because the solo string is converted to a :text argument automatically.
|
217
224
|
|
225
|
+
## How to create an input control
|
218
226
|
|
219
|
-
|
227
|
+
A standard input control is just a tag and options. Take the `text` control, for example.
|
220
228
|
|
221
|
-
|
229
|
+
`text :username, :size=>30, :value=>"joe.e.razsolli"` => `<input name="username" size="30" value="joe.e.razsolli" type="text" />`
|
222
230
|
|
223
|
-
|
231
|
+
The button, color, date, datetime_local, email, hidden, image, month, number, password, range, reset, search, submit, tel, text, time, url, and week tags all work the that way.
|
224
232
|
|
225
|
-
|
233
|
+
The textarea control, on the other hand, puts it's value between the tags, so it uses a :text attribute instead of a :value attribute.
|
226
234
|
|
227
|
-
|
235
|
+
`textarea :username, :size=>30, :text="joe.e.razsolli` => `<textarea name="username" size="30">joe.e.razsolli</textarea>`
|
228
236
|
|
229
|
-
|
237
|
+
The textarea tag can take its text from a block, also.
|
230
238
|
|
231
|
-
|
239
|
+
`textarea(:username, :size=>30) { "joe.e.razsolli" }` => `<textarea name="username" size="30">joe.e.razsolli</textarea>`
|
232
240
|
|
233
|
-
|
234
|
-
puts (Demeler.build(nil, true) do
|
235
|
-
div :class=>"div-class" do
|
236
|
-
"..."
|
237
|
-
end
|
238
|
-
end)
|
241
|
+
Notice for the block form, you have to enclose the parameters to the textarea call in parenthesis.
|
239
242
|
|
240
|
-
|
241
|
-
<div class="div-class">
|
242
|
-
...
|
243
|
-
</div>
|
244
|
-
<!-- end generated output -->
|
245
|
-
```
|
246
|
-
#### tag
|
243
|
+
## How to Create a Checkbox, Radio, or Select Control
|
247
244
|
|
248
|
-
|
245
|
+
For a checkbox, radio, or select control, use the formats below.
|
249
246
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
247
|
+
`checkbox(:vehicle, opts, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")` =>
|
248
|
+
```html
|
249
|
+
<input name="vehicle[1]" type="checkbox" value="volvo">Volvo</input>
|
250
|
+
<input name="vehicle[2]" type="checkbox" value="saab">Saab</input>
|
251
|
+
<input name="vehicle[3]" type="checkbox" value="mercedes">Mercedes</input>
|
252
|
+
<input name="vehicle[4]" type="checkbox" value="audi">Audi</input>
|
253
|
+
```
|
254
254
|
|
255
|
-
|
256
|
-
|
257
|
-
|
255
|
+
`radio(:vehicle, opts, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")` =>
|
256
|
+
```html
|
257
|
+
<input name="vehicle" type="radio" value="volvo">Volvo</input>
|
258
|
+
<input name="vehicle" type="radio" value="saab">Saab</input>
|
259
|
+
<input name="vehicle" type="radio" value="mercedes">Mercedes</input>
|
260
|
+
<input name="vehicle" type="radio" value="audi">Audi</input>
|
258
261
|
```
|
259
262
|
|
260
|
-
|
263
|
+
`select(:vehicle, opts, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")` =>
|
264
|
+
```html
|
265
|
+
<select name="vehicle">
|
266
|
+
<option value="volvo">Volvo</option>
|
267
|
+
<option value="saab">Saab</option>
|
268
|
+
<option value="mercedes">Mercedes</option>
|
269
|
+
<option value="audi">Audi</option>
|
270
|
+
</select>
|
271
|
+
```
|
261
272
|
|
262
|
-
|
273
|
+
Opts represents a Hash with tag attributes.
|
263
274
|
|
264
|
-
```ruby
|
265
|
-
puts (Demeler.build(nil, true) do
|
266
|
-
p "This is a paragraph."
|
267
|
-
end)
|
268
275
|
|
269
|
-
<!-- begin generated output -->
|
270
|
-
<p>This is a paragraph.</p>
|
271
|
-
<!-- end generated output -->
|
272
|
-
```
|
273
276
|
|
274
|
-
|
277
|
+
## Reference Guide
|
278
|
+
|
279
|
+
### def self.build(obj=nil, gen_html=false, session={}, &block)
|
280
|
+
|
281
|
+
This is the main Demeler call used to build your HTML. This call uses your code in the block, so it makes no sense to call `build` without a block.
|
282
|
+
|
283
|
+
Name | Type | Value
|
284
|
+
---- | ---- | -----
|
285
|
+
obj | Hash+ | An object to use to get values and error messages.
|
286
|
+
gen_html | Boolean | Create formatted HTML (true), or compact HTML (false: default).
|
287
|
+
session | Hash | A variable meant to pass a session in a web server, but you can use it for passing any other value as well. _This value is for the caller's use and is not used by Demeler._
|
288
|
+
block | Proc | The block with your code.
|
289
|
+
|
290
|
+
### def initialize(obj=nil, session={}, &block)
|
291
|
+
|
292
|
+
Initialize sets up the initial conditions in Demeler, and is called by `new`.
|
293
|
+
|
294
|
+
Name | Type | Value
|
295
|
+
---- | ---- | -----
|
296
|
+
obj | Hash+ | An object to use to get values and error messages.
|
297
|
+
session | Hash | A variable meant to pass a session in a web server, but you can use it for passing any other value as well. _This value is for the caller's use and is not used by Demeler._
|
298
|
+
block | Proc | The block with your code.
|
299
|
+
|
300
|
+
### def clear
|
301
|
+
|
302
|
+
Clear resets the output variables in order to reuse Demeler without having to reinstantiate it.
|
303
|
+
|
304
|
+
### method_missing(meth, *args, &block)
|
305
|
+
|
306
|
+
This is a Ruby method which catches method calls that have no real method. For example, when you code a `body` tag, there is no method in Demeler to handle that, so it is caught be `missing_method`. Missing_method passes the call along to `tag_generator` to be coded.
|
307
|
+
|
308
|
+
Name | Type | Value
|
309
|
+
---- | ---- | -----
|
310
|
+
meth | Symbol | The name of the missing method being caught.
|
311
|
+
*args | Array | An array of arguments from the call that was intercepted. Tag_generator will try to make sense of them.
|
312
|
+
block | Proc | The block with your code.
|
313
|
+
|
314
|
+
### def p(*args, &block)
|
315
|
+
|
316
|
+
The `p` method is a workaround to make 'p' tags work in `build`.
|
317
|
+
|
318
|
+
Name | Type | Value
|
319
|
+
---- | ---- | -----
|
320
|
+
*args | Array | An array of arguments from the call that was intercepted. Tag_generator will try to make sense of them.
|
321
|
+
block | Proc | The block with your code.
|
322
|
+
|
323
|
+
### def alink(text, args={})
|
324
|
+
|
325
|
+
The `alink` method is a shortcut to build an `a` tag. You could also write a `a` tag like so:
|
275
326
|
|
276
327
|
```ruby
|
277
|
-
|
278
|
-
|
279
|
-
end
|
328
|
+
Demeler.build do
|
329
|
+
a(:href=>"/") { "Home" }
|
330
|
+
end
|
331
|
+
```
|
280
332
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
333
|
+
but the alink method is a shortcut. Code it like this:
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
Demeler.build do
|
337
|
+
alink("Home", :href=>"/")
|
338
|
+
end
|
285
339
|
```
|
286
340
|
|
287
|
-
|
341
|
+
Yes, I know. Six of one, half-dozen of another. It had a legacy beginning, and I kept it in here.
|
288
342
|
|
289
|
-
|
343
|
+
Name | Type | Value
|
344
|
+
---- | ---- | -----
|
345
|
+
text | String | The text to be inserted into the tag.
|
346
|
+
*args | Hash | An hash of attributes which must include the :href attribute.
|
290
347
|
|
291
|
-
|
348
|
+
### def checkbox(name, opts, values)
|
292
349
|
|
293
|
-
|
350
|
+
This is a shortcut to build `checkbox` tags. A properly formed check box is created for each value in the `values` list. If the form object has one or more values set, those boxes will be checked.
|
294
351
|
|
352
|
+
Each check box name will begin with `name` and have a number added, beginning with 1.
|
295
353
|
|
296
|
-
|
354
|
+
Name | Type | Value
|
355
|
+
---- | ---- | -----
|
356
|
+
name | Symbol | The name of the control. It will be prepended with a number.
|
357
|
+
opts | Hash | The attributes and options for the control.
|
358
|
+
values | Hash | The names and values of the check boxes.
|
297
359
|
|
298
|
-
|
360
|
+
The data value in the form object may be a String, Array or Hash. If this is a string, the values are comma separated. If this is an array, the elements are the values. If this is a hash, the values (right hand side of each pair) are the values.
|
299
361
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
text :username
|
304
|
-
end)
|
362
|
+
### radio(name, opts, values)
|
363
|
+
|
364
|
+
This is a shortcut to build radio buttons. All the radio buttons in a set are named the same, and only vary in value. Unlike the checkbox control, the radio control only has one value at a time. The opts are applied to each radio button.
|
305
365
|
|
366
|
+
Name | Type | Value
|
367
|
+
---- | ---- | -----
|
368
|
+
name | Symbol | The name of the control.
|
369
|
+
opts | Hash | The attributes and options for the control.
|
370
|
+
values | Hash | The names and values of the radio boxes.
|
371
|
+
|
372
|
+
The data value in the form object may be a String, Array or Hash. If this is a string, the values are comma separated. If this is an array, the elements are the values. If this is a hash, the values (right hand side of each pair) are the values.
|
373
|
+
|
374
|
+
### def select(name, opts, values)
|
375
|
+
|
376
|
+
The select control is unique in that it has `select` tags surrounding a list of `option` tags. Based on the attributes (opts), you can create a pure dropdown list, or a scrolling list. See https://www.w3schools.com for more info on HTML.
|
377
|
+
|
378
|
+
Name | Type | Value
|
379
|
+
---- | ---- | -----
|
380
|
+
name | Symbol | The name of the control.
|
381
|
+
opts | Hash | The attributes and options for the control.
|
382
|
+
values | Hash | The names and values of the radio boxes.
|
383
|
+
|
384
|
+
The data value in the form object may be a String, Array or Hash. If this is a string, the values are comma separated. If this is an array, the elements are the values. If this is a hash, the values (right hand side of each pair) are the values.
|
385
|
+
|
386
|
+
### def submit(text, opts={})
|
387
|
+
|
388
|
+
The submit shortcut creates a `input` control of type 'submit'.
|
389
|
+
|
390
|
+
Name | Type | Value
|
391
|
+
---- | ---- | -----
|
392
|
+
text | String | The text displayed on the face of the button.
|
393
|
+
opts | Hash | The attributes and options for the control.
|
394
|
+
|
395
|
+
### def tag_generator(meth, args=[], &block)
|
396
|
+
|
397
|
+
You don't normally call `tag_generator` (although you can if you wish to). Tag_generator has many forms which are documented one by one below.
|
398
|
+
|
399
|
+
### def tag_generator(meth, opts, &block)
|
400
|
+
|
401
|
+
This form is used for most simple input controls.
|
402
|
+
|
403
|
+
Name | Type | Value
|
404
|
+
---- | ---- | -----
|
405
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
406
|
+
opts | Hash | The attributes, i.e., :class="user-class", etc.
|
407
|
+
block | Proc | The block
|
408
|
+
|
409
|
+
### def tag_generator(meth, &block)
|
410
|
+
|
411
|
+
This form is used for most simple controls which have no options specified.
|
412
|
+
|
413
|
+
Name | Type | Value
|
414
|
+
---- | ---- | -----
|
415
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
416
|
+
block | Proc | The block
|
417
|
+
|
418
|
+
### def tag_generator(meth, [text], &block)
|
419
|
+
|
420
|
+
This form is used for controls which consist of text between opening and closing tags.
|
421
|
+
|
422
|
+
Name | Type | Value
|
423
|
+
---- | ---- | -----
|
424
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
425
|
+
text | String | The string becomes the :text=>string attribute.
|
426
|
+
block | Proc | The block
|
427
|
+
|
428
|
+
### def tag_generator(meth, [name], &block)
|
429
|
+
|
430
|
+
This form is used for simple input controls which have only a name, i.e., `text(:username)`. You would use a control like this with a form object probably.
|
431
|
+
|
432
|
+
Name | Type | Value
|
433
|
+
---- | ---- | -----
|
434
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
435
|
+
name | Symbol | The name of the control.
|
436
|
+
block | Proc | The block
|
437
|
+
|
438
|
+
### def tag_generator(meth, [opts], &block)
|
439
|
+
|
440
|
+
This form is used for simple input controls which have only a name, i.e., `text(:username)`. You would use a control like this with a form object probably. This option is equivalent to the first option which is the same except the opts are not in an array.
|
441
|
+
|
442
|
+
Name | Type | Value
|
443
|
+
---- | ---- | -----
|
444
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
445
|
+
opts | Hash | The attributes, i.e., :class="user-class", etc.
|
446
|
+
block | Proc | The block
|
447
|
+
|
448
|
+
### def tag_generator(meth, [name, opts], &block)
|
449
|
+
|
450
|
+
This form is the same as the preceeding one, except the name is specified seperately for convenience.
|
451
|
+
|
452
|
+
Name | Type | Value
|
453
|
+
---- | ---- | -----
|
454
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
455
|
+
name | Symbol | The name of the control.
|
456
|
+
opts | Hash | The attributes, i.e., :class="user-class", etc.
|
457
|
+
block | Proc | The block
|
458
|
+
|
459
|
+
### def tag_generator(meth, [name, text], &block)
|
460
|
+
|
461
|
+
This form is the same as the preceeding one, except the text is placed between opening and closing tages, but if the meth is 'label', a `for="text"` attribute is created; otherwise, a `name="text"`. (This is the call that implements `label` tags, obviously.)
|
462
|
+
|
463
|
+
Name | Type | Value
|
464
|
+
---- | ---- | -----
|
465
|
+
meth | Symbol | The method, i.e., the tag name: :p, :br, :input, etc.
|
466
|
+
name | Symbol | The name of the control.
|
467
|
+
text | String | The string becomes the :text=>string attribute.
|
468
|
+
block | Proc | The block
|
469
|
+
|
470
|
+
## How the form object is harvested
|
471
|
+
|
472
|
+
For Demeler to pick up data from the form object and automatically set `value` attributes, you need to have the following conditions:
|
473
|
+
|
474
|
+
* There must be a `name` attribute;
|
475
|
+
* There must be a form object given in the `build` or `new` method;
|
476
|
+
* The form object must contain the named key in the object's hash; and
|
477
|
+
* The retrieved data must not be `nil` and, if the retrieved data is a String, it must not be `empty`.
|
478
|
+
|
479
|
+
The data will create a:
|
480
|
+
|
481
|
+
* (for `textarea`) :text attribute; or
|
482
|
+
* (for all others) :value attribute.
|
483
|
+
|
484
|
+
## Outputting the HTML
|
485
|
+
|
486
|
+
There are two ways to output the HTML: formatted and compressed.
|
487
|
+
|
488
|
+
Formatted code is human readable, like this:
|
489
|
+
|
490
|
+
```html
|
306
491
|
<!-- begin generated output -->
|
307
|
-
<
|
308
|
-
<
|
492
|
+
<select name="vehicle" class="x">
|
493
|
+
<option value="volvo">Volvo</option>
|
494
|
+
<option value="saab">Saab</option>
|
495
|
+
<option value="mercedes">Mercedes</option>
|
496
|
+
<option value="audi">Audi</option>
|
497
|
+
</select>
|
309
498
|
<!-- end generated output -->
|
310
499
|
```
|
311
500
|
|
312
|
-
|
501
|
+
whereas compressed code looks like this:
|
502
|
+
|
503
|
+
```html
|
504
|
+
<select name=\"vehicle\" class=\"x\"><option value=\"volvo\">Volvo</option><option value=\"saab\">Saab</option><option value=\"mercedes\">Mercedes</option><option value=\"audi\">Audi</option></select>
|
505
|
+
```
|
506
|
+
|
507
|
+
Compressed HTML is faster to generate, and is recommended for production.
|
313
508
|
|
314
509
|
## A Bigger Example of a Demeler Script
|
315
510
|
|
data/lib/demeler.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
# Ruby Sequel.
|
22
22
|
|
23
23
|
class Demeler
|
24
|
-
attr_reader :out, :obj
|
24
|
+
attr_reader :out, :obj, :session
|
25
25
|
|
26
26
|
# These calls are effectively generated in the same way as 'text' input
|
27
27
|
# tags. Method_missing just does a substitution to implement them.
|
@@ -33,10 +33,13 @@ class Demeler
|
|
33
33
|
# The default way to start building your markup.
|
34
34
|
# Takes a block and returns the markup.
|
35
35
|
#
|
36
|
+
# @param [object] obj a Sequel::Model object, or Hash object with an added 'errors' field.
|
37
|
+
# @param [boolean] gen_html A flag to control final output: true=>formatted, false=>compressed.
|
38
|
+
# @param [Hash] session The session variable from the caller, although it can be anything because Demeler doesn't use it.
|
36
39
|
# @param [Proc] block
|
37
40
|
#
|
38
|
-
def self.build(obj=nil, gen_html=false, &block)
|
39
|
-
demeler = self.new(obj, &block)
|
41
|
+
def self.build(obj=nil, gen_html=false, session={}, &block)
|
42
|
+
demeler = self.new(obj, session, &block)
|
40
43
|
if gen_html then demeler.to_html else demeler.to_s end
|
41
44
|
end
|
42
45
|
|
@@ -48,6 +51,8 @@ class Demeler
|
|
48
51
|
# A note of warning: you'll get extra spaces in textareas if you use .to_html.
|
49
52
|
#
|
50
53
|
# @param [object] obj--a Sequel::Model object, or Hash object with an added 'errors' field.
|
54
|
+
# @param [Hash] session The session variable from the caller, although it can be anything because Demeler doesn't use it.
|
55
|
+
# @param [Proc] block
|
51
56
|
#
|
52
57
|
# To use this without Sequel, you can use an object like this:
|
53
58
|
# class Obj<Hash
|
@@ -57,9 +62,10 @@ class Demeler
|
|
57
62
|
# end
|
58
63
|
# end
|
59
64
|
#
|
60
|
-
def initialize(obj=nil, &block)
|
65
|
+
def initialize(obj=nil, session={}, &block)
|
61
66
|
raise ArgumentError.new("The object passed to Demeler must have an errors field containing a Hash") if obj && !defined?(obj.errors)
|
62
67
|
@obj = obj
|
68
|
+
@session = session
|
63
69
|
clear
|
64
70
|
instance_eval(&block) if block_given?
|
65
71
|
end
|
@@ -71,6 +77,7 @@ class Demeler
|
|
71
77
|
@level = 0
|
72
78
|
@out = []
|
73
79
|
@labels = []
|
80
|
+
self
|
74
81
|
end
|
75
82
|
|
76
83
|
##
|
@@ -103,13 +110,14 @@ class Demeler
|
|
103
110
|
end
|
104
111
|
|
105
112
|
##
|
106
|
-
# The #alink method simplyfies the generation of <a>...</a> tags
|
113
|
+
# The #alink method simplyfies the generation of <a>...</a> tags.
|
107
114
|
#
|
115
|
+
# @param [String] The link line to be displayed
|
108
116
|
# @param [Array] args Extra arguments that should be processed before
|
109
117
|
# creating the 'a' tag.
|
110
118
|
# @param [Proc] block
|
111
119
|
#
|
112
|
-
def alink(text, args={})
|
120
|
+
def alink(text, args={})Hash
|
113
121
|
raise ArgumentError.new("In Demeler#alink, expected String for argument 1, text") if !text.kind_of?(String)
|
114
122
|
raise ArgumentError.new("In Demeler#alink, expected Hash for argument 2, opts") if !args.kind_of?(Hash)
|
115
123
|
raise ArgumentError.new("In Demeler#alink, expected an href option in opts") if !args[:href]
|
@@ -162,10 +170,12 @@ class Demeler
|
|
162
170
|
##
|
163
171
|
# The radio shortcut
|
164
172
|
#
|
165
|
-
# @param [
|
173
|
+
# @param [Symbol] name Base Name of the control (numbers 1..n will be added)
|
174
|
+
# @param [Hash] opts Attributes for the control
|
175
|
+
# @param [Hash] value=>nomenclature pairs
|
166
176
|
#
|
167
177
|
# @example
|
168
|
-
# g.radio(:
|
178
|
+
# g.radio(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
|
169
179
|
#
|
170
180
|
# @note: first argument is the :name; without the name, the radio control won't work
|
171
181
|
#
|
@@ -190,7 +200,7 @@ class Demeler
|
|
190
200
|
#
|
191
201
|
# @param [Symbol] name The name of the SELECT statement
|
192
202
|
# @param [Hash] opts Options for the SELECT statement
|
193
|
-
# @param [Hash]
|
203
|
+
# @param [Hash] values A list of :name=>value pairs the control will have
|
194
204
|
#
|
195
205
|
# @example
|
196
206
|
# g.select(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
|
@@ -198,14 +208,13 @@ class Demeler
|
|
198
208
|
# @note: first argument is the :name=>"vehicle"
|
199
209
|
# @note: the second argument is a Hash or nil
|
200
210
|
#
|
201
|
-
def select(name,
|
211
|
+
def select(name, args, values)
|
202
212
|
raise ArgumentError.new("In Demeler#select, expected Symbol for argument 1, name") if !name.kind_of?(Symbol)
|
203
|
-
raise ArgumentError.new("In Demeler#select, expected Hash for argument 2,
|
213
|
+
raise ArgumentError.new("In Demeler#select, expected Hash for argument 2, args") if !args.kind_of?(Hash)
|
204
214
|
raise ArgumentError.new("In Demeler#select, expected Hash for argument 3, values") if !values.kind_of?(Hash)
|
205
|
-
opts = {:name=>name}
|
206
|
-
opts.merge!(opts)
|
215
|
+
opts = {:name=>name}.merge(args)
|
207
216
|
data = if @obj then @obj[name] else nil end
|
208
|
-
tag_generator(:select,
|
217
|
+
tag_generator(:select, opts) do
|
209
218
|
values.each do |value,nomenclature|
|
210
219
|
sets = {:value=>value}
|
211
220
|
sets[:selected] = 'true' if data==value.to_s
|
@@ -357,14 +366,6 @@ class Demeler
|
|
357
366
|
@out.join
|
358
367
|
end
|
359
368
|
|
360
|
-
##
|
361
|
-
# This method is part of #to_html below.
|
362
|
-
#
|
363
|
-
def write_html(indent,part)
|
364
|
-
# "<!-- #{indent} --> #{' '*(if indent<0 then 0 else indent end)}#{part}\n"
|
365
|
-
"#{' '*(if indent<0 then 0 else indent end)}#{part}\n"
|
366
|
-
end
|
367
|
-
|
368
369
|
##
|
369
370
|
# Method for converting the results of Demeler to a
|
370
371
|
# human readable string. This isn't recommended for
|
@@ -398,4 +399,14 @@ class Demeler
|
|
398
399
|
return html
|
399
400
|
end # to_html
|
400
401
|
|
402
|
+
private
|
403
|
+
|
404
|
+
##
|
405
|
+
# This method is part of #to_html.
|
406
|
+
#
|
407
|
+
def write_html(indent,part)
|
408
|
+
# "<!-- #{indent} --> #{' '*(if indent<0 then 0 else indent end)}#{part}\n"
|
409
|
+
"#{' '*(if indent<0 then 0 else indent end)}#{part}\n"
|
410
|
+
end
|
411
|
+
|
401
412
|
end
|
data/lib/demeler/version.rb
CHANGED
data/notes
CHANGED
@@ -1,13 +1,43 @@
|
|
1
1
|
cd ~/demeler-gem
|
2
|
-
gem build demeler.gemspec
|
3
2
|
|
4
|
-
|
3
|
+
#----------------------------------------
|
5
4
|
|
5
|
+
# To build the gem and install locally
|
6
|
+
gem build demeler.gemspec
|
7
|
+
sudo gem uninstall demeler
|
6
8
|
sudo gem install demeler
|
7
9
|
|
8
10
|
#----------------------------------------
|
9
11
|
|
10
12
|
To run tests (with 'bacon' installed):
|
11
|
-
|
12
13
|
bacon -Ilib spec/demeler.rb
|
13
14
|
|
15
|
+
#----------------------------------------
|
16
|
+
|
17
|
+
# To set globals in Git
|
18
|
+
git config --global user.name "Michael J. Welch, Ph.D."
|
19
|
+
git config --global user.email mjwelchphd@gmail.com
|
20
|
+
git config --global core.editor xed
|
21
|
+
git config --list
|
22
|
+
|
23
|
+
#----------------------------------------
|
24
|
+
|
25
|
+
# To push up to GitHub
|
26
|
+
git remote add origin https://github.com/mjwelchphd/demeler.git
|
27
|
+
git push -u origin master
|
28
|
+
|
29
|
+
#----------------------------------------
|
30
|
+
|
31
|
+
# To upload the gem to rubygems.org
|
32
|
+
gem push demeler-1.0.1.gem
|
33
|
+
|
34
|
+
#----------------------------------------
|
35
|
+
|
36
|
+
# To run 'irb' for testing
|
37
|
+
cd ~/demeler-gem
|
38
|
+
irb -Ilib
|
39
|
+
|
40
|
+
require_relative 'lib/demeler'
|
41
|
+
load './lib/demeler.rb'
|
42
|
+
|
43
|
+
|
data/spec/demeler.rb
CHANGED
@@ -57,8 +57,8 @@ describe "Simple Demeler with no Object" do
|
|
57
57
|
|
58
58
|
it "should be a plain select control" do
|
59
59
|
@d.clear
|
60
|
-
@d.select(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
|
61
|
-
@d.to_s.should.equal "<select name=\"vehicle\"><option value=\"volvo\">Volvo</option><option value=\"saab\">Saab</option><option value=\"mercedes\">Mercedes</option><option value=\"audi\">Audi</option></select>"
|
60
|
+
@d.select(:vehicle, {:class=>"select-class"}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
|
61
|
+
@d.to_s.should.equal "<select name=\"vehicle\" class=\"select-class\"><option value=\"volvo\">Volvo</option><option value=\"saab\">Saab</option><option value=\"mercedes\">Mercedes</option><option value=\"audi\">Audi</option></select>"
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should be a plain submit control" do
|
@@ -74,7 +74,19 @@ describe "Simple Demeler with no Object" do
|
|
74
74
|
@d.text(:username)
|
75
75
|
@d.to_s.should.equal "<input type=\"submit\" value=\"Go!\" /><label for=\"username\">Enter Username</label><input name=\"username\" type=\"text\" id=\"username\" />"
|
76
76
|
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "Simple Demeler with Session" do
|
80
|
+
session = {:id=>1}
|
81
|
+
before do
|
82
|
+
@d = Demeler.new(nil, session)
|
83
|
+
end
|
77
84
|
|
85
|
+
it "should pass through the session variable" do
|
86
|
+
@d.clear
|
87
|
+
@d.out << session.inspect
|
88
|
+
@d.to_s.should.equal "{:id=>1}"
|
89
|
+
end
|
78
90
|
end
|
79
91
|
|
80
92
|
describe "Complex Demeler with Object" do
|
@@ -332,5 +344,4 @@ describe "Complex Demeler with Object" do
|
|
332
344
|
@d.tag_generator(:input, {:name=>:err, :value=>"bobama", :type=>:text})
|
333
345
|
@d.to_html.should.equal "<!-- begin generated output -->\n<input name=\"err\" value=\"bobama\" type=\"text\" /><warn> <-- Username already used.</warn>\n<!-- end generated output -->\n"
|
334
346
|
end
|
335
|
-
|
336
347
|
end
|