demeler 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60dd5907473caf7a0f8963ed8a5ef41c7c56ba7a
4
+ data.tar.gz: 9ef767a5cbf325bf6456b2a08d1b9a668e0317b7
5
+ SHA512:
6
+ metadata.gz: 885c065028088be8c1d2545c3cd31d755b9a9cf6a1dc747a376cf8c1502bd12647ba12a59abf14b07016689446c37f3da10473c153387c919d0fea824dd01ee6
7
+ data.tar.gz: 4409d084b43ec05c2ccd3060023840a237695ed0038acfedc00c7f91088d60f3366a441f19437526bda1926edbdb7f30b35bbc67acc0901d9a4b4cf9ad17b7f2
data/.gitignore ADDED
File without changes
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ # 1.0.0
2
+ * Initial version.
data/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ # The MIT License (MIT)
2
+
3
+ ## Copyright ©2017 Michael J. Welch, Ph.D.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:
6
+
7
+ ###The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.
8
+
9
+ ###THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.
data/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # Demeler Gem
2
+
3
+ ### Copyright (c) 2017 Michael J Welch, Ph.D. mjwelchphd@gmail.com
4
+ All files in this distribution are subject to the terms of the MIT license.
5
+
6
+ This gem builds HTML code on-the-fly. The advantages are: (1) HTML code is properly formed with respect to tags and nesting; and (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 (3) if there are errors, the error message is generated also.
7
+
8
+ 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
+
10
+ This class doesn't depend on any particular framework, but I use it with Ruby Sequel.
11
+
12
+
13
+ ## The Demeler gem generates HTML from three inputs:
14
+ * 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
17
+
18
+ Let's start with the most basic form, a simple example. Run `irb` and enter this:
19
+
20
+ ```ruby
21
+ require 'demeler'
22
+ html = Demeler.build(nil,true) do
23
+ html do
24
+ head do
25
+ title "Hello, World!"
26
+ end
27
+ body do
28
+ h1 "Hello, World!"
29
+ end
30
+ end
31
+ end
32
+ puts html
33
+ ```
34
+
35
+ You'll get the html code like this:
36
+
37
+ ```html
38
+ <!-- begin generated output -->
39
+ <html>
40
+ <head>
41
+ <title>Hello, World!</title>
42
+ </head>
43
+ <body>
44
+ <h1>Hello, World!</h1>
45
+ </body>
46
+ </html>
47
+ <!-- end generated output -->
48
+ ```
49
+
50
+ ### Why bother with Demeler? Why not just write HTML?
51
+
52
+ There are several reasons to use this gem:
53
+
54
+ * You write in Ruby code
55
+ * Demeler balances out all the HTML tags
56
+ * Demeler optionally formats the HTML, producing human readable output
57
+ * Demeler can receive an object with data (such as a Sequel::Model object), and automatically insert the values
58
+ * Demeler can insert error messages your controller inserts into the object
59
+
60
+ ## You can also use the gem directly
61
+
62
+ You can instantiate a Demeler object, and call its methods:
63
+
64
+ ```ruby
65
+ require 'demeler'
66
+ d = Demeler.new
67
+ d.html do
68
+ d.head do
69
+ d.title("Hello, World!")
70
+ end
71
+ d.body do
72
+ d.h1("Hello, World!")
73
+ end
74
+ end
75
+ puts d.to_html
76
+ ```
77
+
78
+ ## Fields from an object can be inserted automatically
79
+
80
+ You can automatically load the values from a Sequel::Model object, or you can define an object and use it in place of Sequel. To define an object, use a definition similar to this:
81
+
82
+ ```ruby
83
+ class Obj<Hash
84
+ attr_accessor :errors
85
+ def initialize
86
+ @errors = {}
87
+ end
88
+ end
89
+ ```
90
+
91
+ Your new object is just a Hash+, so you can assign it values like this:
92
+
93
+ ```ruby
94
+ obj = Obj.new
95
+ obj[:username] = "michael"
96
+ obj[:password] = "my-password"
97
+ ```
98
+
99
+ The object can now be used to fill `input` fields in a form:
100
+
101
+ ```ruby
102
+ html = Demeler.build(obj,true) do
103
+ text :username
104
+ password :password
105
+ end
106
+ puts html
107
+ ```
108
+
109
+ That code will automatically insert the values from `obj` for you.
110
+
111
+ > _NOTE: When the first argument is a symbol, it is used as the name of the field._
112
+
113
+ ```html
114
+ <!-- begin generated output -->
115
+ <input name="username" type="text" value="michael" />
116
+ <input name="password" type="password" value="my-password" />
117
+ <!-- end generated output -->
118
+ ```
119
+
120
+ ### Demeler creates error messages, too
121
+
122
+ You can put an error message into the object you created if your validation finds something wrong. Just insert a Hash element with the name of the element, and an array of lines, thusly:
123
+
124
+ ```ruby
125
+ obj = Obj.new
126
+ obj[:username] = "michael"
127
+ obj[:password] = "my-password"
128
+ obj.errors[:username] = ["This username is already taken"]
129
+
130
+ html = Demeler.build(obj,true) do
131
+ text :username
132
+ password :password
133
+ end
134
+ puts html
135
+ ```
136
+
137
+ This will generate the HTML with the added message, as well:
138
+
139
+ ```html
140
+ <!-- begin generated output -->
141
+ <input name="username" type="text" value="michael" /><warn> <-- This username is already taken</warn>
142
+ <input name="password" type="password" value="my-password" />
143
+ <!-- end generated output -->
144
+ ```
145
+
146
+ Notice that the error is surrounded by `<warn>...</warn>` tags. You can define how you want those to format the message using CSS. For example, if you just want the message to be displayed in red, use:
147
+
148
+ ```ruby
149
+ style "warn {color: red;}"
150
+ ```
151
+
152
+ in your Demeler code like this:
153
+
154
+ ```ruby
155
+ html = Demeler.build(obj,true) do
156
+ style "warn {color: red;}"
157
+ text :username
158
+ password :password
159
+ end
160
+ puts html
161
+ ```
162
+
163
+ ## Adding attributes to your tags
164
+
165
+ You can add attributes by just adding them to the end of the tag. For example, if I want the username input tag to display in with a blue background, I can use:
166
+
167
+ ```ruby
168
+ html = Demeler.build(obj,true) do
169
+ style ".blue {color: blue;}"
170
+ text :username, :class=>"blue"
171
+ password :password
172
+ end
173
+ puts html
174
+ ```
175
+
176
+ The HTML code generated will be:
177
+
178
+ ```html
179
+ <!-- begin generated output -->
180
+ <style>.blue {color: blue;}</style>
181
+ <input name="username" class="blue" type="text" value="michael" /><warn> <-- This username is already taken</warn>
182
+ <input name="password" type="password" value="my-password" />
183
+ <!-- end generated output -->
184
+ ```
185
+
186
+ Any attribute can be added in this way.
187
+
188
+ ## Embedding text between tags on one line
189
+
190
+ Normally, anything in brackets {} is embedded like this: `p{"Some text."}` yields:
191
+
192
+ ```html
193
+ <!-- begin generated output -->
194
+ <p>
195
+ Some text.
196
+ </p>
197
+ <!-- end generated output -->
198
+ ```
199
+
200
+ You can make it come out on one line by using the :text attribute: `p :text=>"Some text."` yields:
201
+
202
+ ```html
203
+ <!-- begin generated output -->
204
+ <p>Some text.</p>
205
+ <!-- end generated output -->
206
+ ```
207
+
208
+ In most cases, this can be achieved just by eliminating the {}: `p "Some text." yields:
209
+
210
+ ```html
211
+ <!-- begin generated output -->
212
+ <p>Some text.</p>
213
+ <!-- end generated output -->
214
+ ```
215
+
216
+ This is because the solo string is converted to a :text argument automatically.
217
+
218
+
219
+ ## Demeler Interface Definitions
220
+
221
+ The Demeler gem accepts any random tag you want to give it, but non-input tags and input tags are treated differently. Input tags are :button, :checkbox, :color, :date, :datetime_local, :email, :hidden, :image, :month, :number, :password, :range, :radio, :reset, :search, :select, :submit, :tel, :text, :time, :url, and :week. All other tags are non-input tags.
222
+
223
+ Input tags are treated differently because they have special characteristics, like automatically setting from a form object passed to Demeler. Therefore, we'll start with non-input tags first.
224
+
225
+ Non-input tags can accept a variety of parameter arrangements to allow for different situations. Each different situation is described below, and there are examples to help you understand.
226
+
227
+ ### Non-Input Tag Parameter Formats
228
+
229
+ #### tag opts
230
+
231
+ _Opts is a Hash with attributes._
232
+
233
+ ```ruby
234
+ puts (Demeler.build(nil, true) do
235
+ div :class=>"div-class" do
236
+ "..."
237
+ end
238
+ end)
239
+
240
+ <!-- begin generated output -->
241
+ <div class="div-class">
242
+ ...
243
+ </div>
244
+ <!-- end generated output -->
245
+ ```
246
+ #### tag
247
+
248
+ _A solo tag._
249
+
250
+ ```ruby
251
+ puts (Demeler.build(nil, true) do
252
+ br
253
+ end)
254
+
255
+ <!-- begin generated output -->
256
+ <br />
257
+ <!-- end generated output -->
258
+ ```
259
+
260
+ #### tag string
261
+
262
+ _A solo string._
263
+
264
+ ```ruby
265
+ puts (Demeler.build(nil, true) do
266
+ p "This is a paragraph."
267
+ end)
268
+
269
+ <!-- begin generated output -->
270
+ <p>This is a paragraph.</p>
271
+ <!-- end generated output -->
272
+ ```
273
+
274
+ _Or for longer text, you can use the block format._
275
+
276
+ ```ruby
277
+ puts (Demeler.build(nil, true) do
278
+ p { "Un débris de hameau où quatre maisons fleuries d'orchis émergent des blés drus et hauts. Ce sont les Bastides Blanches, à mi-chemin entre la plaine et le grand désert lavandier, à l'ombre des monts de Lure. C'est là que vivent douze personnes, deux ménages, plus Gagou l'innocent." }
279
+ end)
280
+
281
+ <!-- begin generated output -->
282
+ <p>
283
+ Un débris de hameau où quatre maisons fleuries d'orchis émergent des blés drus et hauts. Ce sont les Bastides Blanches, à mi-chemin entre la plaine et le grand désert lavandier, à l'ombre des monts de Lure. C'est là que vivent douze personnes, deux ménages, plus Gagou l'innocent.
284
+ </p>
285
+ ```
286
+
287
+ #### tag symbol
288
+
289
+ _The symbol is used as the name of the tag._ This option is used with input tags (see below).
290
+
291
+ #### tag symbol, hash
292
+
293
+ _This option generates_
294
+
295
+
296
+ #### tag symbol, string
297
+
298
+ _This option generates a tag with the name **symbol**, and the string between beginning and ending tags. If the tag is a :label, and the `label for` matches an `input name`, if the `input` has no `id`, one will be added.
299
+
300
+ ```ruby
301
+ puts (Demeler.build(nil, true) do
302
+ label :username, "Enter Username"
303
+ text :username
304
+ end)
305
+
306
+ <!-- begin generated output -->
307
+ <label for="username">Enter Username</label>
308
+ <input name="username" type="text" id="username" />
309
+ <!-- end generated output -->
310
+ ```
311
+
312
+ _Tags other than `label` will have a `name` attribute instead of a `for` attribute._
313
+
314
+ ## A Bigger Example of a Demeler Script
315
+
316
+ ### Generate a login screen.
317
+
318
+ This example will be expanded in the future.
319
+
320
+ The Ruby code:
321
+
322
+ ```ruby
323
+ html = Demeler.build(nil,true) do
324
+ h1("Please Login")
325
+ form(:method=>:post, :action=>"/authenticate") do
326
+ table do
327
+ tr do
328
+ td { label(:username, "User Name") }
329
+ td { text(:username, :size=>30) }
330
+ end
331
+
332
+ tr do
333
+ td { label(:password, "Password") }
334
+ td { password(:password, :size=>30) }
335
+ end
336
+
337
+ tr do
338
+ td {}
339
+ td { submit("Log In") }
340
+ end
341
+ end
342
+ end
343
+ p { alink("Forgot password?", :href=>"/forgot") }
344
+ end
345
+ ```
346
+
347
+ The generated HTML:
348
+
349
+ ```html
350
+ <!-- begin generated output -->
351
+ <h1>Please Login</h1>
352
+ <form method="post" action="/authenticate">
353
+ <table>
354
+ <tr>
355
+ <td>
356
+ <label for="username">User Name</label>
357
+ </td>
358
+ <td>
359
+ <input name="username" size="30" type="text" id="username" />
360
+ </td>
361
+ </tr>
362
+ <tr>
363
+ <td>
364
+ <label for="password">Password</label>
365
+ </td>
366
+ <td>
367
+ <input name="password" size="30" type="password" id="password" />
368
+ </td>
369
+ </tr>
370
+ <tr>
371
+ <td>
372
+ </td>
373
+ <td>
374
+ <input type="submit" value="Log In" />
375
+ </td>
376
+ </tr>
377
+ </table>
378
+ </form>
379
+ <p>
380
+ <a href="/forgot">Forgot password?</a>
381
+ </p>
382
+ <!-- end generated output -->
383
+ ```
data/demeler.gemspec ADDED
@@ -0,0 +1,15 @@
1
+ require_relative File.dirname(__FILE__) + '/lib/demeler/version'
2
+ include Version
3
+ Gem::Specification.new do |s|
4
+ s.author = "Michael J. Welch, Ph.D."
5
+ s.files = Dir.glob(["CHANGELOG.md", "LICENSE.md", "README.md", "demeler.gemspec", "lib/*", "lib/demeler/*", "notes", "spec/*", ".gitignore"])
6
+ s.name = 'demeler'
7
+ s.require_paths = ["lib"]
8
+ s.summary = 'Yet another HTML generator.'
9
+ s.version = VERSION
10
+ s.date = MODIFIED
11
+ s.email = 'mjwelchphd@gmail.com'
12
+ s.homepage = 'http://rubygems.org/gems/demeler'
13
+ s.license = 'MIT'
14
+ s.description = "This gem takes your ruby input, plus an object such as a Sequel::Model object, and generates HTML code. If the object has values, they're inserted into the HTML, and if the object has error messages, code is generated to display them. You can use CSS, but it's not automated in this class of methods."
15
+ end
@@ -0,0 +1,4 @@
1
+ module Version
2
+ VERSION = "1.0.0"
3
+ MODIFIED = "2017-06-10"
4
+ end
data/lib/demeler.rb ADDED
@@ -0,0 +1,401 @@
1
+ # Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com
2
+ # Copyright (c) 2017 Michael J Welch, Ph.D. mjwelchphd@gmail.com
3
+ # All files in this distribution are subject to the terms of the MIT license.
4
+ #
5
+ # This work was based on Fellinger's Gestalt and Blueform, but is essentially
6
+ # a completely new version which is not a drop-in replacement for either.
7
+ # There's probably less than a dozen lines of Fellinger's original code left here.
8
+ # Nevertheless, the basic concept is Fellinger's, and it's a good one.
9
+ #
10
+ # This gem builds HTML code on-the-fly. The advantages are: (1) HTML code is
11
+ # properly formed with respect to tags and nesting; and (2) the code is dynamic,
12
+ # i.e., values from an object containing data (if used) are automatically
13
+ # extracted and inserted into the resultant HTML code, and if there are errors,
14
+ # the error message is generated also.
15
+ #
16
+ # The French word démêler means "to unravel," and that's sort of what this gem
17
+ # does. It unravels your inputs to form HTML code. The diacritical marks are
18
+ # not used in the name for compatibility.
19
+ #
20
+ # This class doesn't depend on any particular framework, but I use it with
21
+ # Ruby Sequel.
22
+
23
+ class Demeler
24
+ attr_reader :out, :obj
25
+
26
+ # These calls are effectively generated in the same way as 'text' input
27
+ # tags. Method_missing just does a substitution to implement them.
28
+ MethodsLikeInputText = [:button, :color, :date, :datetime_local, :email, \
29
+ :hidden, :image, :month, :number, :password, :range, :reset, :search, \
30
+ :submit, :tel, :text, :time, :url, :week]
31
+
32
+ ##
33
+ # The default way to start building your markup.
34
+ # Takes a block and returns the markup.
35
+ #
36
+ # @param [Proc] block
37
+ #
38
+ def self.build(obj=nil, gen_html=false, &block)
39
+ demeler = self.new(obj, &block)
40
+ if gen_html then demeler.to_html else demeler.to_s end
41
+ end
42
+
43
+ ##
44
+ # Demeler.new builds HTML from Ruby code.
45
+ # You can either access #out, .to_s or .to_html to
46
+ # return the actual markup.
47
+ #
48
+ # A note of warning: you'll get extra spaces in textareas if you use .to_html.
49
+ #
50
+ # @param [object] obj--a Sequel::Model object, or Hash object with an added 'errors' field.
51
+ #
52
+ # To use this without Sequel, you can use an object like this:
53
+ # class Obj<Hash
54
+ # attr_accessor :errors
55
+ # def initialize
56
+ # @errors = {}
57
+ # end
58
+ # end
59
+ #
60
+ def initialize(obj=nil, &block)
61
+ raise ArgumentError.new("The object passed to Demeler must have an errors field containing a Hash") if obj && !defined?(obj.errors)
62
+ @obj = obj
63
+ clear
64
+ instance_eval(&block) if block_given?
65
+ end
66
+
67
+ ##
68
+ # Clear out the data in order to start over with the same Demeler obj
69
+ #
70
+ def clear
71
+ @level = 0
72
+ @out = []
73
+ @labels = []
74
+ end
75
+
76
+ ##
77
+ # Catch tag calls that have not been pre-defined.
78
+ #
79
+ # @param [String] meth The method that was called.
80
+ # @param [Hash] args Additional arguments passed to the called method.
81
+ # @param [Proc] block.
82
+ #
83
+ def method_missing(meth, *args, &block)
84
+ # This code allows for some input tags that work like <input type="text" ...> to
85
+ # work--for example g.password works in place of g.input(:type=>:password, ...)
86
+ if MethodsLikeInputText.index(meth) # TODO!
87
+ args << {} if !args[-1].kind_of?(Hash)
88
+ args.last[:type] = meth
89
+ meth = :input
90
+ end
91
+ tag_generator(meth, args, &block)
92
+ end
93
+
94
+ ##
95
+ # Workaround for Kernel#p to make <p /> tags possible.
96
+ #
97
+ # @param [Hash] args Extra arguments that should be processed before
98
+ # creating the paragraph tag.
99
+ # @param [Proc] block
100
+ #
101
+ def p(*args, &block)
102
+ tag_generator(:p, args, &block)
103
+ end
104
+
105
+ ##
106
+ # The #alink method simplyfies the generation of <a>...</a> tags
107
+ #
108
+ # @param [Array] args Extra arguments that should be processed before
109
+ # creating the 'a' tag.
110
+ # @param [Proc] block
111
+ #
112
+ def alink(text, args={})
113
+ raise ArgumentError.new("In Demeler#alink, expected String for argument 1, text") if !text.kind_of?(String)
114
+ raise ArgumentError.new("In Demeler#alink, expected Hash for argument 2, opts") if !args.kind_of?(Hash)
115
+ raise ArgumentError.new("In Demeler#alink, expected an href option in opts") if !args[:href]
116
+ opts = args.clone
117
+ opts[:text] = text
118
+ tag_generator(:a, opts)
119
+ end
120
+
121
+ ##
122
+ # The checkbox shortcut
123
+ #
124
+ # @param [Symbol] name Base Name of the control (numbers 1..n will be added)
125
+ # @param [Hash] opts Attributes for the control
126
+ # @param [Hash] value=>nomenclature pairs
127
+ #
128
+ # @example
129
+ # g.checkbox(:vehicle, opts, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
130
+ # @object [Sequel::Model]
131
+ #
132
+ #
133
+ # @note: first argument becomes the :name plus a number starting at 1, i.e., "vehicle1", etc.
134
+ #
135
+ def checkbox(name, opts, values)
136
+ raise ArgumentError.new("In Demeler#checkbox, expected Symbol for argument 1, name") if !name.kind_of?(Symbol)
137
+ raise ArgumentError.new("In Demeler#checkbox, expected Hash for argument 2, opts") if !opts.kind_of?(Hash)
138
+ raise ArgumentError.new("In Demeler#checkbox, expected Hash for argument 3, values") if !values.kind_of?(Hash)
139
+ n = 0
140
+ data = if @obj then @obj[name] else nil end
141
+ case data.class.name
142
+ when "String"
143
+ data = data.split(",")
144
+ when "Array"
145
+ # it's alreay in the form we want
146
+ when "Hash"
147
+ data = data.values
148
+ else
149
+ data = nil
150
+ end
151
+ values.each do |value,nomenclature|
152
+ sets = opts.clone
153
+ sets[:name] = "#{name}[#{n+=1}]".to_sym
154
+ sets[:type] = :checkbox
155
+ sets[:value] = value
156
+ sets[:text] = nomenclature
157
+ sets[:checked] = 'true' if data && data.index(value.to_s)
158
+ tag_generator(:input, sets)
159
+ end
160
+ end
161
+
162
+ ##
163
+ # The radio shortcut
164
+ #
165
+ # @param [Hash] args Attributes for the control
166
+ #
167
+ # @example
168
+ # g.radio(:name=>:vehicle, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
169
+ #
170
+ # @note: first argument is the :name; without the name, the radio control won't work
171
+ #
172
+ def radio(name, opts, values)
173
+ raise ArgumentError.new("In Demeler#radio, expected Symbol for argument 1, name") if !name.kind_of?(Symbol)
174
+ raise ArgumentError.new("In Demeler#radio, expected Hash for argument 2, opts") if !opts.kind_of?(Hash)
175
+ raise ArgumentError.new("In Demeler#radio, expected Hash for argument 3, values") if !values.kind_of?(Hash)
176
+ data = if @obj then @obj[name] else nil end
177
+ values.each do |value,nomenclature|
178
+ sets = opts.clone
179
+ sets[:name] = "#{name}".to_sym
180
+ sets[:type] = :radio
181
+ sets[:value] = value
182
+ sets[:text] = nomenclature
183
+ sets[:checked] = 'true' if data==value.to_s
184
+ tag_generator(:input, sets)
185
+ end
186
+ end
187
+
188
+ ##
189
+ # The select (select_tag) shortcut
190
+ #
191
+ # @param [Symbol] name The name of the SELECT statement
192
+ # @param [Hash] opts Options for the SELECT statement
193
+ # @param [Hash] args Attributes (OPTIONS) for the SELECT
194
+ #
195
+ # @example
196
+ # g.select(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
197
+ #
198
+ # @note: first argument is the :name=>"vehicle"
199
+ # @note: the second argument is a Hash or nil
200
+ #
201
+ def select(name, opts, values)
202
+ 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, opts") if !opts.kind_of?(Hash)
204
+ 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)
207
+ data = if @obj then @obj[name] else nil end
208
+ tag_generator(:select, [opts]) do
209
+ values.each do |value,nomenclature|
210
+ sets = {:value=>value}
211
+ sets[:selected] = 'true' if data==value.to_s
212
+ sets[:text] = nomenclature
213
+ tag_generator(:option, [sets])
214
+ end
215
+ end
216
+ end
217
+
218
+ ##
219
+ # The submit shortcut
220
+ #
221
+ # @param [String] text The text which the button will display
222
+ # @param [Hash] opts Options for the SUBMIT statement
223
+ #
224
+ # @example
225
+ # g.submit("Accept Changes", {})
226
+ #
227
+ def submit(text, opts={})
228
+ attr = {:type=>:submit}
229
+ attr[:value] = text
230
+ attr.merge!(opts)
231
+ tag_generator(:input, attr)
232
+ end
233
+
234
+ ##
235
+ # The tag_generator method
236
+ #
237
+ # @param [Symbol] meth The type of control to be generated
238
+ # @param [Hash] args Options for the tag being generated
239
+ # @param [Proc] block A block which will be called to get input or nest tags
240
+ #
241
+ # @note The :text option will insert text between the opening and closing tag;
242
+ # It's useful to create one-line tags with text inserted.
243
+ #
244
+ def tag_generator(meth, args=[], &block)
245
+ # this check catches a loop before it bombs the Demeler class
246
+ raise StandardError.new("looping on #{meth.inspect}, @out=#{@out.inspect}") if (@level += 1)>500
247
+
248
+ # This part examines the variations in possible inputs,
249
+ # and rearranges them to suit tag_generator
250
+ case
251
+ when args.kind_of?(Hash)
252
+ # args is a hash (attributes only)
253
+ attr = args
254
+ when args.size==0
255
+ # args is empty array
256
+ attr = {}
257
+ when args.size==1 && args[0].kind_of?(String)
258
+ # args is array of 1 string
259
+ attr = {:text=>args[0]}
260
+ when args.size==1 && args[0].kind_of?(Symbol)
261
+ # args is array of 1 symbol (used as 'name')
262
+ attr = {:name=>args[0]}
263
+ when args.size==1 && args[0].kind_of?(Hash)
264
+ # args is array of 1 hash (same as args is a hash)
265
+ attr = args[0]
266
+ when args.size==2 && args[0].kind_of?(Symbol) && args[1].kind_of?(Hash)
267
+ # args is an array of symbol ('name') and hash ('attributes')
268
+ # both name and attributes, i.e., g.div(:list, :class=>'list-class')
269
+ attr = {:name=>args[0]}.merge(args[1])
270
+ when args.size==2 && args[0].kind_of?(Symbol) && args[1].kind_of?(String)
271
+ # args is array of symbol ('name') and string ('text')
272
+ # both name and text, i.e., g.label(:list, "List")
273
+ case meth
274
+ when :label
275
+ attr = {:for=>args[0]}.merge({:text=>args[1]})
276
+ @labels << args[0]
277
+ else
278
+ attr = {:name=>args[0]}.merge({:text=>args[1]})
279
+ end
280
+ else
281
+ raise ArgumentError.new("Too many arguments in Demeler#tag_generator: meth=>#{meth.inspect}, args=>#{args.inspect}")
282
+ end
283
+
284
+ # This part extracts a value out of the form's object (if any)
285
+ name = attr[:name]
286
+ case
287
+ when name.nil?
288
+ when @obj.nil?
289
+ when !attr[:value].nil?
290
+ when @obj[name].nil?
291
+ when @obj[name].kind_of?(String) && @obj[name].empty?
292
+ when meth==:textarea
293
+ attr[:text] = @obj[name] if !attr.has_key?(:text)
294
+ else
295
+ attr[:value] = @obj[name] if !attr.has_key?(:value)
296
+ end
297
+
298
+ # If a label was previously defined for this :input,
299
+ # add an :id attribute automatically
300
+ attr[:id] = name if meth==:input && !attr.has_key?(:id) && @labels.index(name)
301
+
302
+ # This part extracts the text (if any)--the text
303
+ # is used in place of a block for tags like 'label'
304
+ text = attr.delete(:text)
305
+ case
306
+ when text.nil?
307
+ text = []
308
+ when text.kind_of?(String)
309
+ text = [text]
310
+ when text.kind_of?(Array)
311
+ else
312
+ raise ArgumentError.new("In Demeler#tag_generator, expected Array or String for text (value for textarea, or ")
313
+ end
314
+
315
+ # make sure there's at least one (empty) string for textarea because
316
+ # a textarea tag with no "block" makes the browser act wierd, even if it's
317
+ # self-closing, i.e., <textarea ... />
318
+ text = [""] if meth==:textarea && text.empty? && !block_given?
319
+
320
+ # In case there is an error message for this field,
321
+ # prepare the message now to add following the field
322
+ if @obj && (list = @obj.errors[name])
323
+ raise ArgumentError.new("The error message, if any, must be an array of Strings") if !list.kind_of?(Array)
324
+ error = if [:input, :select].index(meth) then list.first else nil end
325
+ message = if error then "<warn> <-- #{error}</warn>" else nil end
326
+ else
327
+ message = ""
328
+ end
329
+
330
+ # This is where the actual HTML is generated--it's structured this
331
+ # way to be sure that only WHOLE tags are placed into @out--it's
332
+ # done this way to facilitate #to_html
333
+ case
334
+ when !text.empty?
335
+ temp = text.join("\n")
336
+ @out << "<#{meth}#{attr.map{|k,v| %[ #{k}="#{v}"]}.join}>#{temp}</#{meth}>#{message}"
337
+ when block_given?
338
+ @out << "<#{meth}#{attr.map{|k,v| %[ #{k}="#{v}"]}.join}>"
339
+ temp = yield
340
+ @out << temp if temp && temp.kind_of?(String)
341
+ @out << "</#{meth}>#{message}"
342
+ else
343
+ @out << "<#{meth}#{attr.map{|k,v| %[ #{k}="#{v}"]}.join} />#{message}"
344
+ end
345
+
346
+ @level -= 1
347
+ nil
348
+ end
349
+
350
+ ##
351
+ # Convert the final output of Demeler to a string.
352
+ # This method has the following alias: "to_str".
353
+ #
354
+ # @return [String]
355
+ #
356
+ def to_s
357
+ @out.join
358
+ end
359
+
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
+ # Method for converting the results of Demeler to a
370
+ # human readable string. This isn't recommended for
371
+ # production because it requires much more time to
372
+ # generate the HTML output than to_s.
373
+ #
374
+ # @return [String] The formatted form output
375
+ #
376
+ def to_html
377
+ # output the segments, but adjust the indentation
378
+ indent = 0
379
+ html = "<!-- begin generated output -->\n"
380
+ @out.each do |part|
381
+ case
382
+ when part =~ /^<\/.*>$/
383
+ indent -= 1
384
+ html << write_html(indent,part)
385
+ when part =~ /^<.*<\/.*>$/
386
+ html << write_html(indent,part)
387
+ when part =~ /^<.*\/>$/
388
+ html << write_html(indent,part)
389
+ when part =~ /^<.*>$/
390
+ html << write_html(indent,part)
391
+ indent += 1
392
+ else
393
+ html << write_html(indent,part)
394
+ end
395
+ end
396
+ # return the formatted string
397
+ html << "<!-- end generated output -->\n"
398
+ return html
399
+ end # to_html
400
+
401
+ end
data/notes ADDED
@@ -0,0 +1,13 @@
1
+ cd ~/demeler-gem
2
+ gem build demeler.gemspec
3
+
4
+ sudo gem uninstall demeler
5
+
6
+ sudo gem install demeler
7
+
8
+ #----------------------------------------
9
+
10
+ To run tests (with 'bacon' installed):
11
+
12
+ bacon -Ilib spec/demeler.rb
13
+
data/spec/demeler.rb ADDED
@@ -0,0 +1,336 @@
1
+ require "demeler"
2
+ require "bacon"
3
+
4
+ # bacon -Ilib spec/demeler.rb
5
+
6
+ class Obj<Hash
7
+ attr_accessor :errors
8
+ def initialize
9
+ @errors = {}
10
+ end
11
+ end
12
+
13
+ describe "Simple Demeler with no Object" do
14
+ before do
15
+ @d = Demeler.new
16
+ end
17
+
18
+ it "should be empty" do
19
+ @d.out.should.be.empty
20
+ end
21
+
22
+ it "should return p" do
23
+ @d.clear
24
+ @d.p
25
+ @d.to_s.should.equal "<p />"
26
+ end
27
+
28
+ it "should return p with embedded text" do
29
+ @d.clear
30
+ @d.p { "ABC" }
31
+ @d.to_s.should.equal "<p>ABC</p>"
32
+ end
33
+
34
+ it "should return p with embedded HTML" do
35
+ @d.clear
36
+ @d.p { @d.br }
37
+ @d.to_s.should.equal "<p><br /></p>"
38
+ end
39
+
40
+ it "should be a plain link" do
41
+ @d.clear
42
+ @d.alink("Registration", :href=>"registration")
43
+ @d.to_s.should.equal "<a href=\"registration\">Registration</a>"
44
+ end
45
+
46
+ it "should be a plain checkbox control" do
47
+ @d.clear
48
+ @d.checkbox(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
49
+ @d.to_s.should.equal "<input name=\"vehicle[1]\" type=\"checkbox\" value=\"volvo\">Volvo</input><input name=\"vehicle[2]\" type=\"checkbox\" value=\"saab\">Saab</input><input name=\"vehicle[3]\" type=\"checkbox\" value=\"mercedes\">Mercedes</input><input name=\"vehicle[4]\" type=\"checkbox\" value=\"audi\">Audi</input>"
50
+ end
51
+
52
+ it "should be a plain radio control" do
53
+ @d.clear
54
+ @d.radio(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
55
+ @d.to_s.should.equal "<input name=\"vehicle\" type=\"radio\" value=\"volvo\">Volvo</input><input name=\"vehicle\" type=\"radio\" value=\"saab\">Saab</input><input name=\"vehicle\" type=\"radio\" value=\"mercedes\">Mercedes</input><input name=\"vehicle\" type=\"radio\" value=\"audi\">Audi</input>"
56
+ end
57
+
58
+ it "should be a plain select control" do
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>"
62
+ end
63
+
64
+ it "should be a plain submit control" do
65
+ @d.clear
66
+ @d.submit("Go!")
67
+ @d.to_s.should.equal "<input type=\"submit\" value=\"Go!\" />"
68
+ end
69
+
70
+ it "should add an :id if there is a matching label" do
71
+ @d.clear
72
+ @d.submit("Go!")
73
+ @d.label(:username, "Enter Username")
74
+ @d.text(:username)
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
+ end
77
+
78
+ end
79
+
80
+ describe "Complex Demeler with Object" do
81
+ before do
82
+ obj = Obj.new
83
+ obj[:a_button] = "Push Me"
84
+ obj[:a_checkbox1] = {"2"=>"saab","4"=>"audi"}
85
+ obj[:a_checkbox2] = ["saab", "mercedes"]
86
+ obj[:a_checkbox3] = "volvo,mercedes"
87
+ obj[:a_color] = "#00FF00"
88
+ obj[:a_date1] = "2017-06-01"
89
+ obj[:a_date2] = "2017-07-02"
90
+ obj[:an_email] = "mike@czarmail.com"
91
+ obj[:a_hidden] = "hidden_data"
92
+ obj[:a_month] = "2017-06"
93
+ obj[:a_number] = "3"
94
+ obj[:a_password] = "fricken-password"
95
+ obj[:a_radio] = "saab"
96
+ obj[:a_range] = 2
97
+ obj[:a_search] = "search for this"
98
+ obj[:a_tel] = "951-929-2015"
99
+ obj[:a_text] = "This is just scat."
100
+ obj[:a_textarea1] = "Text for area 1."
101
+ obj[:a_textarea2] = "More text for area 2.\nThis text has multiple lines."
102
+ obj[:a_textarea4] = "Line 1"
103
+ obj[:a_time] = "23:24"
104
+ obj[:a_url] = "https://www.czarmail.com"
105
+ obj[:a_week] = "2018-W03"
106
+
107
+ @d = Demeler.new(obj)
108
+ end
109
+
110
+ it "generate a style block" do
111
+ @d.clear
112
+ @d.style { "red { color: red; } warn { color: red; }" }
113
+ @d.to_s.should.equal "<style>red { color: red; } warn { color: red; }</style>"
114
+ end
115
+
116
+ it "should be a button control with data" do
117
+ @d.clear
118
+ @d.button(:name=>:a_button)
119
+ @d.to_s.should.equal "<input name=\"a_button\" type=\"button\" value=\"Push Me\" />"
120
+ end
121
+
122
+ it "should be a checkbox control with data" do
123
+ @d.clear
124
+ @d.checkbox(:a_checkbox1, {:class=>:check_class}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
125
+ @d.to_s.should.equal "<input class=\"check_class\" name=\"a_checkbox1[1]\" type=\"checkbox\" value=\"volvo\">Volvo</input><input class=\"check_class\" name=\"a_checkbox1[2]\" type=\"checkbox\" value=\"saab\" checked=\"true\">Saab</input><input class=\"check_class\" name=\"a_checkbox1[3]\" type=\"checkbox\" value=\"mercedes\">Mercedes</input><input class=\"check_class\" name=\"a_checkbox1[4]\" type=\"checkbox\" value=\"audi\" checked=\"true\">Audi</input>"
126
+ end
127
+
128
+ it "should be a color control with data" do
129
+ @d.clear
130
+ @d.color(:a_color)
131
+ @d.to_s.should.equal "<input name=\"a_color\" type=\"color\" value=\"#00FF00\" />"
132
+ end
133
+
134
+ it "should be a date control with data" do
135
+ @d.clear
136
+ @d.date(:a_date1)
137
+ @d.to_s.should.equal "<input name=\"a_date1\" type=\"date\" value=\"2017-06-01\" />"
138
+ end
139
+
140
+ it "should be a date control with data and class" do
141
+ @d.clear
142
+ @d.date(:a_date2, :class=>:date_class)
143
+ @d.to_s.should.equal "<input name=\"a_date2\" class=\"date_class\" type=\"date\" value=\"2017-07-02\" />"
144
+ end
145
+
146
+ it "should be a text control with data" do
147
+ @d.clear
148
+ @d.email(:an_email)
149
+ @d.to_s.should.equal "<input name=\"an_email\" type=\"email\" value=\"mike@czarmail.com\" />"
150
+ end
151
+
152
+ it "should be a hidden field with data" do
153
+ @d.clear
154
+ @d.hidden(:a_hidden, :value=>3)
155
+ @d.to_s.should.equal "<input name=\"a_hidden\" value=\"3\" type=\"hidden\" />"
156
+ end
157
+
158
+ it "should be an image button" do
159
+ @d.clear
160
+ @d.image(:src=>"images/czar-mail-logo.svg", :width=>80, :height=>30)
161
+ @d.to_s.should.equal "<input src=\"images/czar-mail-logo.svg\" width=\"80\" height=\"30\" type=\"image\" />"
162
+ end
163
+
164
+ it "should be an image control" do
165
+ @d.clear
166
+ @d.img(:src=>"images/czar-mail-logo.svg", :width=>80, :height=>30)
167
+ @d.to_s.should.equal "<img src=\"images/czar-mail-logo.svg\" width=\"80\" height=\"30\" />"
168
+ end
169
+
170
+ it "should be a month control with data" do
171
+ @d.clear
172
+ @d.month(:a_month)
173
+ @d.to_s.should.equal "<input name=\"a_month\" type=\"month\" value=\"2017-06\" />"
174
+ end
175
+
176
+ it "should be a number control with data" do
177
+ @d.clear
178
+ @d.number(:a_number, :min=>1, :max=>5)
179
+ @d.to_s.should.equal "<input name=\"a_number\" min=\"1\" max=\"5\" type=\"number\" value=\"3\" />"
180
+ end
181
+
182
+ it "should be a password control with data" do
183
+ @d.clear
184
+ @d.password(:a_password)
185
+ @d.to_s.should.equal "<input name=\"a_password\" type=\"password\" value=\"fricken-password\" />"
186
+ end
187
+
188
+ it "should be a radio control with data" do
189
+ @d.clear
190
+ @d.radio(:a_radio, {:class=>:radio_class}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")
191
+ @d.to_s.should.equal "<input class=\"radio_class\" name=\"a_radio\" type=\"radio\" value=\"volvo\">Volvo</input><input class=\"radio_class\" name=\"a_radio\" type=\"radio\" value=\"saab\" checked=\"true\">Saab</input><input class=\"radio_class\" name=\"a_radio\" type=\"radio\" value=\"mercedes\">Mercedes</input><input class=\"radio_class\" name=\"a_radio\" type=\"radio\" value=\"audi\">Audi</input>"
192
+ end
193
+
194
+ it "should be a range control with data" do
195
+ @d.clear
196
+ @d.range(:a_range, :min=>1, :max=>10)
197
+ @d.to_s.should.equal "<input name=\"a_range\" min=\"1\" max=\"10\" type=\"range\" value=\"2\" />"
198
+ end
199
+
200
+ it "should be a reset control" do
201
+ @d.clear
202
+ @d.reset
203
+ @d.to_s.should.equal "<input type=\"reset\" />"
204
+ end
205
+
206
+ it "should be a search control with data" do
207
+ @d.clear
208
+ @d.search(:a_search)
209
+ @d.to_s.should.equal "<input name=\"a_search\" type=\"search\" value=\"search for this\" />"
210
+ end
211
+
212
+ it "should be a submit control" do
213
+ @d.clear
214
+ @d.submit("Go!", :name=>:a_submit)
215
+ @d.to_s.should.equal "<input type=\"submit\" value=\"Go!\" name=\"a_submit\" />"
216
+ end
217
+
218
+ it "should be a tel (telephone) control with data" do
219
+ @d.clear
220
+ @d.tel(:a_tel)
221
+ @d.to_s.should.equal "<input name=\"a_tel\" type=\"tel\" value=\"951-929-2015\" />"
222
+ end
223
+
224
+ it "should be a text control with data" do
225
+ @d.clear
226
+ @d.text(:a_text, :size=>20)
227
+ @d.to_s.should.equal "<input name=\"a_text\" size=\"20\" type=\"text\" value=\"This is just scat.\" />"
228
+ end
229
+
230
+ it "should be a textarea (1) control with data" do
231
+ @d.clear
232
+ @d.textarea(:a_textarea1, :rows=>4, :cols=>50)
233
+ @d.to_s.should.equal "<textarea name=\"a_textarea1\" rows=\"4\" cols=\"50\">Text for area 1.</textarea>"
234
+ end
235
+
236
+ it "should be a textarea (2) control with data" do
237
+ @d.clear
238
+ @d.textarea(:a_textarea2, :rows=>4, :cols=>50) {'2'}
239
+ @d.to_s.should.equal "<textarea name=\"a_textarea2\" rows=\"4\" cols=\"50\">More text for area 2.\nThis text has multiple lines.</textarea>"
240
+ end
241
+
242
+ it "should be a textarea (3) control with NO data" do
243
+ @d.clear
244
+ @d.textarea(:a_textarea3, :rows=>4, :cols=>50, :text=>["Line 1","Line 2","Line 3"])
245
+ @d.to_s.should.equal "<textarea name=\"a_textarea3\" rows=\"4\" cols=\"50\">Line 1\nLine 2\nLine 3</textarea>"
246
+ end
247
+
248
+ it "should be a textarea (4) control with data" do
249
+ @d.clear
250
+ @d.textarea(:a_textarea4, :rows=>4, :cols=>50)
251
+ @d.to_s.should.equal "<textarea name=\"a_textarea4\" rows=\"4\" cols=\"50\">Line 1</textarea>"
252
+ end
253
+
254
+ it "should be a time control with data" do
255
+ @d.clear
256
+ @d.time(:a_time)
257
+ @d.to_s.should.equal "<input name=\"a_time\" type=\"time\" value=\"23:24\" />"
258
+ end
259
+
260
+ it "should be a url control with data" do
261
+ @d.clear
262
+ @d.url(:a_url)
263
+ @d.to_s.should.equal "<input name=\"a_url\" type=\"url\" value=\"https://www.czarmail.com\" />"
264
+ end
265
+
266
+ it "should be a week control with data" do
267
+ @d.clear
268
+ @d.week(:a_week)
269
+ @d.to_s.should.equal "<input name=\"a_week\" type=\"week\" value=\"2018-W03\" />"
270
+ end
271
+
272
+ it "should be a red tag with data" do
273
+ @d.clear
274
+ @d.red(:text=>"This ought to be red.")
275
+ @d.to_s.should.equal "<red>This ought to be red.</red>"
276
+ end
277
+
278
+ #=== Demeler Calls =====================================
279
+
280
+ it "should be demeler: args is a hash (attributes only)" do
281
+ @d.clear
282
+ @d.tag_generator(:div, {:class=>"div-class"}) { "..." }
283
+ @d.to_s.should.equal "<div class=\"div-class\">...</div>"
284
+ end
285
+
286
+ it "should be demeler: args is empty array" do
287
+ @d.clear
288
+ @d.tag_generator(:br, [])
289
+ @d.to_s.should.equal "<br />"
290
+ end
291
+
292
+ it "should be demeler: args is array of 1 string" do
293
+ @d.clear
294
+ @d.tag_generator(:textarea, ["Some text to edit."])
295
+ @d.to_s.should.equal "<textarea>Some text to edit.</textarea>"
296
+ end
297
+
298
+ it "should be demeler: args is array of 1 symbol (used as 'name')" do
299
+ @d.clear
300
+ @d.tag_generator(:div, [:div_name]) { "..." }
301
+ @d.to_s.should.equal "<div name=\"div_name\">...</div>"
302
+ end
303
+
304
+ it "should be demeler: args is array of 1 hash (same as args is a hash)" do
305
+ @d.clear
306
+ @d.tag_generator(:div, [{:class=>"div-name"}]) { "..." }
307
+ @d.to_s.should.equal "<div class=\"div-name\">...</div>"
308
+ end
309
+
310
+ it "should be demeler: args is an array of symbol ('name') and hash ('attributes')" do
311
+ @d.clear
312
+ @d.tag_generator(:div, [:list, :class=>'list-class']) { "..." }
313
+ @d.to_s.should.equal "<div name=\"list\" class=\"list-class\">...</div>"
314
+ end
315
+
316
+ it "should be demeler: args is array of symbol ('name') and string ('text' or 'for')" do
317
+ @d.clear
318
+ @d.tag_generator(:label, [:list, "List"])
319
+ @d.to_s.should.equal "<label for=\"list\">List</label>"
320
+ end
321
+
322
+ it "should have an error message" do
323
+ @d.clear
324
+ @d.obj.errors[:err] = ["Username already used."]
325
+ @d.tag_generator(:input, {:name=>:err, :value=>"bobama", :type=>:text})
326
+ @d.to_s.should.equal "<input name=\"err\" value=\"bobama\" type=\"text\" /><warn> <-- Username already used.</warn>"
327
+ end
328
+
329
+ it "should create user friendly HTML" do
330
+ @d.clear
331
+ @d.obj.errors[:err] = ["Username already used."]
332
+ @d.tag_generator(:input, {:name=>:err, :value=>"bobama", :type=>:text})
333
+ @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
+ end
335
+
336
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: demeler
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael J. Welch, Ph.D.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This gem takes your ruby input, plus an object such as a Sequel::Model
14
+ object, and generates HTML code. If the object has values, they're inserted into
15
+ the HTML, and if the object has error messages, code is generated to display them.
16
+ You can use CSS, but it's not automated in this class of methods.
17
+ email: mjwelchphd@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".gitignore"
23
+ - CHANGELOG.md
24
+ - LICENSE.md
25
+ - README.md
26
+ - demeler.gemspec
27
+ - lib/demeler.rb
28
+ - lib/demeler/version.rb
29
+ - notes
30
+ - spec/demeler.rb
31
+ homepage: http://rubygems.org/gems/demeler
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.5.1
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Yet another HTML generator.
55
+ test_files: []