rails_errors2html 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,115 @@
1
+ --------------------------------
2
+ NAME
3
+ --------------------------------
4
+ rails_errors2html
5
+
6
+ --------------------------------
7
+ DESCRIPTION
8
+ --------------------------------
9
+
10
+ sane html rendering of active_model errors
11
+
12
+ --------------------------------
13
+ SYNOPSIS
14
+ --------------------------------
15
+
16
+ ````erb
17
+
18
+ <%= form_for @post do %>
19
+
20
+ <!-- these are all the same -->
21
+ <%= @post.errors %>
22
+ <%= @post.errors.to_s %>
23
+ <%= @post.errors.to_html %>
24
+
25
+ <% end %>
26
+
27
+ <!-- you can merge errors from different objects -->
28
+
29
+ <%= Errors2Html.to_html(@post.errors, @comment.errors) %>
30
+
31
+ ````
32
+
33
+ you can override the built-in template like so
34
+
35
+ ````ruby
36
+
37
+ # file : config/initializers/errors2html.rb
38
+
39
+ Errors2Html.template = 'shared/errors'
40
+
41
+ ````
42
+
43
+ here is an example template.
44
+
45
+ note that errors are partioned into global and field based errors.
46
+
47
+
48
+ ````erb
49
+ <!-- file : app/views/shared/errors.html.erb -->
50
+
51
+ <div class="errors2html errors-summary">
52
+ <h4 class="errors-caption">Sorry, we encountered some errors:</h4>
53
+
54
+ <% unless errors.global.empty? %>
55
+ <ul class="errors-global-list">
56
+ <% errors.global.each do |message| %>
57
+ <li class="errors-message">
58
+ <%= message %>
59
+ </li>
60
+ <% end %>
61
+ </ul>
62
+ <% end %>
63
+
64
+ <% unless errors.fields.empty? %>
65
+ <dl class="errors-fields-list">
66
+ <%
67
+ errors.fields.each do |key, messages|
68
+ title = Array(key).join(" ").titleize
69
+ %>
70
+ <dt class="errors-title">
71
+ <%= title %>
72
+ </dt>
73
+
74
+ <% Array(messages).each do |message| %>
75
+ <dd class="errors-message">
76
+ <%= message %>
77
+ </dd>
78
+ <% end %>
79
+ <% end %>
80
+ </dl>
81
+ <% end %>
82
+ </div>
83
+ ````
84
+
85
+
86
+ you might want some css like this
87
+
88
+ ````css
89
+
90
+ .errors-summary {
91
+ box-sizing: border-box;
92
+ width: 100%;
93
+ height: auto;
94
+ color: #333;
95
+ background-color: #fffff6;
96
+ padding: 1em;
97
+ }
98
+ .errors-caption {
99
+ font-weight: bold;
100
+ }
101
+ .errors-title {
102
+ }
103
+ .errors-message {
104
+ }
105
+
106
+ ````
107
+
108
+ --------------------------------
109
+ INSTALL
110
+ --------------------------------
111
+
112
+ gem install rails_errors2html
113
+
114
+ gem 'rails_errors2html'
115
+ bundle install
data/Rakefile ADDED
@@ -0,0 +1,446 @@
1
+ This.name =
2
+ "Errors2Html"
3
+
4
+ This.synopsis =
5
+ "<%= form_for @post do %> <%= @post.errors.to_html %>"
6
+
7
+ This.rubyforge_project = 'codeforpeople'
8
+ This.author = "Ara T. Howard"
9
+ This.email = "ara.t.howard@gmail.com"
10
+ This.homepage = "https://github.com/ahoward/#{ This.lib }"
11
+
12
+ This.setup!
13
+
14
+
15
+
16
+ task :default do
17
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
18
+ end
19
+
20
+ task :test do
21
+ This.run_tests!
22
+ end
23
+
24
+ namespace :test do
25
+ task(:unit){ This.run_tests!(:unit) }
26
+ task(:functional){ This.run_tests!(:functional) }
27
+ task(:integration){ This.run_tests!(:integration) }
28
+ end
29
+
30
+ def This.run_tests!(which = nil)
31
+ which ||= '**'
32
+ test_dir = File.join(This.dir, "test")
33
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
34
+ test_rbs = Dir.glob(test_glob).sort
35
+
36
+ div = ('=' * 119)
37
+ line = ('-' * 119)
38
+
39
+ test_rbs.each_with_index do |test_rb, index|
40
+ testno = index + 1
41
+ command = "#{ File.basename(This.ruby) } -I ./lib -I ./test/lib #{ test_rb }"
42
+
43
+ puts
44
+ This.say(div, :color => :cyan, :bold => true)
45
+ This.say("@#{ testno } => ", :bold => true, :method => :print)
46
+ This.say(command, :color => :cyan, :bold => true)
47
+ This.say(line, :color => :cyan, :bold => true)
48
+
49
+ system(command)
50
+
51
+ This.say(line, :color => :cyan, :bold => true)
52
+
53
+ status = $?.exitstatus
54
+
55
+ if status.zero?
56
+ This.say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
57
+ This.say("SUCCESS", :color => :green, :bold => true)
58
+ else
59
+ This.say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
60
+ This.say("FAILURE", :color => :red, :bold => true)
61
+ end
62
+ This.say(line, :color => :cyan, :bold => true)
63
+
64
+ exit(status) unless status.zero?
65
+ end
66
+ end
67
+
68
+
69
+ task :gemspec do
70
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
71
+ ignore_directories = ['pkg', 'db']
72
+ ignore_files = ['test/log', 'test/db.yml', 'a.rb', 'b.rb'] + Dir['db/*'] + %w'db'
73
+
74
+ shiteless =
75
+ lambda do |list|
76
+ list.delete_if do |entry|
77
+ next unless test(?e, entry)
78
+ extension = File.basename(entry).split(%r/[.]/).last
79
+ ignore_extensions.any?{|ext| ext === extension}
80
+ end
81
+ list.delete_if do |entry|
82
+ next unless test(?d, entry)
83
+ dirname = File.expand_path(entry)
84
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
85
+ end
86
+ list.delete_if do |entry|
87
+ next unless test(?f, entry)
88
+ filename = File.expand_path(entry)
89
+ ignore_files.any?{|file| File.expand_path(file) == filename}
90
+ end
91
+ end
92
+
93
+ lib = This.lib
94
+ object = This.object
95
+ version = This.version
96
+ files = shiteless[Dir::glob("**/**")]
97
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
98
+ #has_rdoc = true #File.exist?('doc')
99
+ test_files = test(?e, "test/#{ lib }.rb") ? "test/#{ lib }.rb" : nil
100
+ summary = This.summary || This.synopsis || "#{ lib } kicks the ass"
101
+ description = This.description || summary
102
+
103
+ if This.extensions.nil?
104
+ This.extensions = []
105
+ extensions = This.extensions
106
+ %w( Makefile configure extconf.rb ).each do |ext|
107
+ extensions << ext if File.exists?(ext)
108
+ end
109
+ end
110
+ extensions = [extensions].flatten.compact
111
+
112
+ # TODO
113
+ if This.dependencies.nil?
114
+ dependencies = []
115
+ else
116
+ case This.dependencies
117
+ when Hash
118
+ dependencies = This.dependencies.values
119
+ when Array
120
+ dependencies = This.dependencies
121
+ end
122
+ end
123
+
124
+ template =
125
+ if test(?e, 'gemspec.erb')
126
+ This.template_for{ IO.read('gemspec.erb') }
127
+ else
128
+ This.template_for {
129
+ <<-__
130
+ ## <%= lib %>.gemspec
131
+ #
132
+
133
+ Gem::Specification::new do |spec|
134
+ spec.name = <%= lib.inspect %>
135
+ spec.version = <%= version.inspect %>
136
+ spec.platform = Gem::Platform::RUBY
137
+ spec.summary = <%= lib.inspect %>
138
+ spec.description = <%= description.inspect %>
139
+
140
+ spec.files =\n<%= files.sort.pretty_inspect %>
141
+ spec.executables = <%= executables.inspect %>
142
+
143
+ spec.require_path = "lib"
144
+
145
+ spec.test_files = <%= test_files.inspect %>
146
+
147
+ <% dependencies.each do |lib_version| %>
148
+ spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
149
+ <% end %>
150
+
151
+ spec.extensions.push(*<%= extensions.inspect %>)
152
+
153
+ spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
154
+ spec.author = <%= This.author.inspect %>
155
+ spec.email = <%= This.email.inspect %>
156
+ spec.homepage = <%= This.homepage.inspect %>
157
+ end
158
+ __
159
+ }
160
+ end
161
+
162
+ FileUtils.mkdir_p(This.pkgdir)
163
+ gemspec = "#{ lib }.gemspec"
164
+ open(gemspec, "w"){|fd| fd.puts(template)}
165
+ This.gemspec = gemspec
166
+ end
167
+
168
+ task :gem => [:clean, :gemspec] do
169
+ FileUtils.mkdir_p(This.pkgdir)
170
+ before = Dir['*.gem']
171
+ cmd = "gem build #{ This.gemspec }"
172
+ `#{ cmd }`
173
+ after = Dir['*.gem']
174
+ gem = ((after - before).first || after.first) or abort('no gem!')
175
+ FileUtils.mv(gem, This.pkgdir)
176
+ This.gem = File.join(This.pkgdir, File.basename(gem))
177
+ end
178
+
179
+ task :readme do
180
+ samples = ''
181
+ prompt = '~ > '
182
+ lib = This.lib
183
+ version = This.version
184
+
185
+ Dir['sample*/*'].sort.each do |sample|
186
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
187
+
188
+ cmd = "cat #{ sample }"
189
+ samples << This.util.indent(prompt + cmd, 2) << "\n\n"
190
+ samples << This.util.indent(`#{ cmd }`, 4) << "\n"
191
+
192
+ cmd = "ruby #{ sample }"
193
+ samples << This.util.indent(prompt + cmd, 2) << "\n\n"
194
+
195
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
196
+ samples << This.util.indent(`#{ cmd } 2>&1`, 4) << "\n"
197
+ end
198
+
199
+ template =
200
+ if test(?e, 'readme.erb')
201
+ This.template_for{ IO.read('readme.erb') }
202
+ else
203
+ This.template_for {
204
+ <<-__
205
+ NAME
206
+ #{ lib }
207
+
208
+ DESCRIPTION
209
+
210
+ INSTALL
211
+ gem install #{ lib }
212
+
213
+ SAMPLES
214
+ #{ samples }
215
+ __
216
+ }
217
+ end
218
+
219
+ open("README", "w"){|fd| fd.puts template}
220
+ end
221
+
222
+
223
+ task :clean do
224
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| FileUtils.rm_rf(entry)}
225
+ end
226
+
227
+
228
+ task :release => [:clean, :gemspec, :gem] do
229
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
230
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
231
+ raise "no gems?" if gems.size < 1
232
+
233
+ cmd = "gem push #{ This.gem }"
234
+ puts cmd
235
+ puts
236
+ system(cmd)
237
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
238
+
239
+ #cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
240
+ #puts cmd
241
+ #puts
242
+ #system(cmd)
243
+ #abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
244
+ end
245
+
246
+
247
+
248
+
249
+
250
+ BEGIN {
251
+ # support for this rakefile
252
+ #
253
+ $VERBOSE = nil
254
+
255
+ require 'erb'
256
+ require 'fileutils'
257
+ require 'rbconfig'
258
+ require 'pp'
259
+
260
+ # cache a bunch of stuff about this rakefile/environment
261
+ #
262
+
263
+ This =
264
+ Class.new(Hash) do
265
+
266
+ def method_missing(method, *args, &block)
267
+ if method.to_s =~ /=/
268
+ key = method.to_s.chomp('=')
269
+ value = block ? block : args.shift
270
+ self[key] = value
271
+ else
272
+ key = method.to_s
273
+ if block
274
+ value = block
275
+ self[key] = value
276
+ else
277
+ value = self[key]
278
+
279
+ if value.respond_to?(:call)
280
+ self[key] = value.call()
281
+ else
282
+ value
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ def inspect
289
+ expand!
290
+ PP.pp(self, '')
291
+ end
292
+
293
+ def expand!
294
+ keys.each do |key|
295
+ value = self[key]
296
+ if value.respond_to?(:call)
297
+ self[key] = value.call()
298
+ end
299
+ end
300
+ end
301
+
302
+ end.new()
303
+
304
+ This.file = File.expand_path(__FILE__)
305
+ This.dir = File.dirname(This.file)
306
+ This.pkgdir = File.join(This.dir, 'pkg')
307
+
308
+ # defaults
309
+ #
310
+ This.lib do
311
+ File.basename(Dir.pwd)
312
+ end
313
+
314
+ def This.setup!
315
+ begin
316
+ require "./lib/#{ This.lib }"
317
+ rescue LoadError
318
+ abort("could not load #{ This.lib }")
319
+ end
320
+ end
321
+
322
+ This.name do
323
+ This.name = This.lib.capitalize
324
+ end
325
+
326
+ This.object do
327
+ begin
328
+ This.object = eval(This.name)
329
+ rescue Object
330
+ abort("could not determine object from #{ This.name }")
331
+ end
332
+ end
333
+
334
+ This.version do
335
+ This.object.send(:version)
336
+ end
337
+
338
+ This.dependencies do
339
+ if This.object.respond_to?(:dependencies)
340
+ This.object.dependencies
341
+ end
342
+ end
343
+
344
+ This.ruby do
345
+ c = Config::CONFIG
346
+ bindir = c["bindir"] || c['BINDIR']
347
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
348
+ ruby_ext = c['EXEEXT'] || ''
349
+ File.join(bindir, (ruby_install_name + ruby_ext))
350
+ end
351
+
352
+ # some utils
353
+ #
354
+ This.util = Module.new do
355
+ def indent(s, n = 2)
356
+ s = unindent(s)
357
+ ws = ' ' * n
358
+ s.gsub(%r/^/, ws)
359
+ end
360
+
361
+ def unindent(s)
362
+ indent = nil
363
+ s.each_line do |line|
364
+ next if line =~ %r/^\s*$/
365
+ indent = line[%r/^\s*/] and break
366
+ end
367
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
368
+ end
369
+
370
+ extend self
371
+ end
372
+
373
+ # template support
374
+ #
375
+ This.template = Class.new do
376
+ def initialize(&block)
377
+ @block = block
378
+ @template = block.call.to_s
379
+ end
380
+
381
+ def expand(b=nil)
382
+ ERB.new(This.util.unindent(@template)).result((b||@block).binding)
383
+ end
384
+
385
+ alias_method 'to_s', 'expand'
386
+ end
387
+
388
+ def This.template_for(*args, &block)
389
+ This.template.new(*args, &block)
390
+ end
391
+
392
+ # colored console output support
393
+ #
394
+ This.ansi = {
395
+ :clear => "\e[0m",
396
+ :reset => "\e[0m",
397
+ :erase_line => "\e[K",
398
+ :erase_char => "\e[P",
399
+ :bold => "\e[1m",
400
+ :dark => "\e[2m",
401
+ :underline => "\e[4m",
402
+ :underscore => "\e[4m",
403
+ :blink => "\e[5m",
404
+ :reverse => "\e[7m",
405
+ :concealed => "\e[8m",
406
+ :black => "\e[30m",
407
+ :red => "\e[31m",
408
+ :green => "\e[32m",
409
+ :yellow => "\e[33m",
410
+ :blue => "\e[34m",
411
+ :magenta => "\e[35m",
412
+ :cyan => "\e[36m",
413
+ :white => "\e[37m",
414
+ :on_black => "\e[40m",
415
+ :on_red => "\e[41m",
416
+ :on_green => "\e[42m",
417
+ :on_yellow => "\e[43m",
418
+ :on_blue => "\e[44m",
419
+ :on_magenta => "\e[45m",
420
+ :on_cyan => "\e[46m",
421
+ :on_white => "\e[47m"
422
+ }
423
+
424
+ def This.say(something, *args)
425
+ options = args.last.is_a?(Hash) ? args.pop : {}
426
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
427
+ keys = options.keys
428
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
429
+
430
+ color = options[:color]
431
+ bold = options.has_key?(:bold)
432
+
433
+ parts = [something]
434
+ parts.unshift(This.ansi[color]) if color
435
+ parts.unshift(This.ansi[:bold]) if bold
436
+ parts.push(This.ansi[:clear]) if parts.size > 1
437
+
438
+ method = options[:method] || :puts
439
+
440
+ Kernel.send(method, parts.join)
441
+ end
442
+
443
+ # always run out of the project dir
444
+ #
445
+ Dir.chdir(This.dir)
446
+ }
@@ -0,0 +1,120 @@
1
+ module Errors2Html
2
+ VERSION = '1.0.0'
3
+
4
+ def Errors2Html.version
5
+ Errors2Html::VERSION
6
+ end
7
+
8
+ def Errors2Html.dependencies
9
+ {
10
+ 'map' => [ 'map' , ' >= 6.2.0' ],
11
+ 'rails_view' => [ 'rails_view' , ' >= 1.0.1' ]
12
+ }
13
+ end
14
+
15
+ begin
16
+ require 'rubygems'
17
+ rescue LoadError
18
+ nil
19
+ end
20
+
21
+ Errors2Html.dependencies.each do |lib, dependency|
22
+ gem(*dependency) if defined?(gem)
23
+ require(lib)
24
+ end
25
+
26
+ class << Errors2Html
27
+ attr_accessor :template
28
+ end
29
+
30
+ def Errors2Html.to_html(*args)
31
+ args.flatten!
32
+ args.compact!
33
+
34
+ at_least_one_error = false
35
+
36
+ errors = Map.new
37
+ errors[:global] = []
38
+ errors[:fields] = {}
39
+
40
+ args.each do |e|
41
+ e.each do |key, messages|
42
+ key = key.to_s
43
+
44
+ Array(messages).each do |message|
45
+ at_least_one_error = true
46
+
47
+ list =
48
+ if key =~ /\A(?:[*]|base)\Z/iomx
49
+ errors[:global] ||= []
50
+ else
51
+ errors[:fields][key] ||= []
52
+ end
53
+
54
+ list.push(message.to_s).uniq!
55
+ end
56
+ end
57
+ end
58
+
59
+ return "" unless at_least_one_error
60
+
61
+ locals = {
62
+ :errors => errors,
63
+ :global_errors => errors.global,
64
+ :fields_errors => errors.fields
65
+ }
66
+
67
+ if template
68
+ View.render(:template => template, :locals => locals)
69
+ else
70
+ View.render(:inline => Template, :locals => locals)
71
+ end
72
+ end
73
+
74
+ def to_html
75
+ Errors2Html.to_html(self)
76
+ end
77
+
78
+ def to_s
79
+ to_html
80
+ end
81
+
82
+ Template = <<-erb
83
+ <div class="errors2html errors-summary">
84
+ <h4 class="errors-caption">Sorry, we encountered some errors:</h4>
85
+
86
+ <% unless errors.global.empty? %>
87
+ <ul class="errors-global-list">
88
+ <% errors.global.each do |message| %>
89
+ <li class="errors-message">
90
+ <%= message %>
91
+ </li>
92
+ <% end %>
93
+ </ul>
94
+ <% end %>
95
+
96
+ <% unless errors.fields.empty? %>
97
+ <dl class="errors-fields-list">
98
+ <%
99
+ errors.fields.each do |key, messages|
100
+ title = Array(key).join(" ").titleize
101
+ %>
102
+ <dt class="errors-title">
103
+ <%= title %>
104
+ </dt>
105
+
106
+ <% Array(messages).each do |message| %>
107
+ <dd class="errors-message">
108
+ <%= message %>
109
+ </dd>
110
+ <% end %>
111
+ <% end %>
112
+ </dl>
113
+ <% end %>
114
+ </div>
115
+ erb
116
+ end
117
+
118
+ require 'active_model' unless defined?(ActiveModel)
119
+ ActiveModel::Errors.send(:include, Errors2Html)
120
+
@@ -0,0 +1,39 @@
1
+ ## rails_errors2html.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "rails_errors2html"
6
+ spec.version = "1.0.0"
7
+ spec.platform = Gem::Platform::RUBY
8
+ spec.summary = "rails_errors2html"
9
+ spec.description = "<%= form_for @post do %> <%= @post.errors.to_html %>"
10
+
11
+ spec.files =
12
+ ["README.md",
13
+ "Rakefile",
14
+ "lib",
15
+ "lib/rails_errors2html.rb",
16
+ "rails_errors2html.gemspec",
17
+ "test",
18
+ "test/rails_errors2html_test.rb",
19
+ "test/testing.rb"]
20
+
21
+ spec.executables = []
22
+
23
+ spec.require_path = "lib"
24
+
25
+ spec.test_files = nil
26
+
27
+
28
+ spec.add_dependency(*["map", " >= 6.2.0"])
29
+
30
+ spec.add_dependency(*["rails_view", " >= 1.0.1"])
31
+
32
+
33
+ spec.extensions.push(*[])
34
+
35
+ spec.rubyforge_project = "codeforpeople"
36
+ spec.author = "Ara T. Howard"
37
+ spec.email = "ara.t.howard@gmail.com"
38
+ spec.homepage = "https://github.com/ahoward/rails_errors2html"
39
+ end
@@ -0,0 +1,44 @@
1
+ require_relative '../lib/rails_errors2html.rb'
2
+ require_relative '../test/testing.rb'
3
+
4
+ Testing Errors2Html do
5
+
6
+ testing 'simple rendering' do
7
+ errors = ActiveModel::Errors.new(base = Map.new)
8
+ errors.add :base, 'error on base'
9
+ errors.add :field, 'error on field'
10
+
11
+ expected = <<-__
12
+ <div class="errors2html errors-summary">
13
+ <h4 class="errors-caption">Sorry, we encountered some errors:</h4>
14
+
15
+ <ul class="errors-global-list">
16
+ <li class="errors-message">
17
+ error on base
18
+ </li>
19
+ </ul>
20
+
21
+ <dl class="errors-fields-list">
22
+ <dt class="errors-title">
23
+ Field
24
+ </dt>
25
+
26
+ <dd class="errors-message">
27
+ error on field
28
+ </dd>
29
+ </dl>
30
+ </div>
31
+ __
32
+
33
+ compress = proc do |string|
34
+ end
35
+
36
+ assert{ compress(errors.to_html) == compress(expected) }
37
+ assert{ compress(errors) == compress(expected) }
38
+ end
39
+
40
+ protected
41
+ def compress(*strings)
42
+ strings.flatten.compact.join.gsub(/\s+/, '')
43
+ end
44
+ end
data/test/testing.rb ADDED
@@ -0,0 +1,197 @@
1
+ # -*- encoding : utf-8 -*-
2
+ #
3
+ require 'test/unit'
4
+
5
+ testdir = File.expand_path(File.dirname(__FILE__))
6
+ rootdir = File.dirname(testdir)
7
+ libdir = File.join(rootdir, 'lib')
8
+
9
+ STDOUT.sync = true
10
+
11
+ $:.unshift(testdir) unless $:.include?(testdir)
12
+ $:.unshift(libdir) unless $:.include?(libdir)
13
+ $:.unshift(rootdir) unless $:.include?(rootdir)
14
+
15
+ class Testing
16
+ class Slug < ::String
17
+ def Slug.for(*args)
18
+ string = args.flatten.compact.join('-')
19
+ words = string.to_s.scan(%r/\w+/)
20
+ words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
21
+ words.delete_if{|word| word.nil? or word.strip.empty?}
22
+ new(words.join('-').downcase)
23
+ end
24
+ end
25
+
26
+ class Context
27
+ attr_accessor :name
28
+
29
+ def initialize(name, *args)
30
+ @name = name
31
+ end
32
+
33
+ def to_s
34
+ Slug.for(name)
35
+ end
36
+ end
37
+ end
38
+
39
+ def Testing(*args, &block)
40
+ Class.new(::Test::Unit::TestCase) do
41
+
42
+ ## class methods
43
+ #
44
+ class << self
45
+ def contexts
46
+ @contexts ||= []
47
+ end
48
+
49
+ def context(*args, &block)
50
+ return contexts.last if(args.empty? and block.nil?)
51
+
52
+ context = Testing::Context.new(*args)
53
+ contexts.push(context)
54
+
55
+ begin
56
+ block.call(context)
57
+ ensure
58
+ contexts.pop
59
+ end
60
+ end
61
+
62
+ def slug_for(*args)
63
+ string = [context, args].flatten.compact.join('-')
64
+ words = string.to_s.scan(%r/\w+/)
65
+ words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
66
+ words.delete_if{|word| word.nil? or word.strip.empty?}
67
+ words.join('-').downcase.sub(/_$/, '')
68
+ end
69
+
70
+ def name() const_get(:Name) end
71
+
72
+ def testno()
73
+ '%05d' % (@testno ||= 0)
74
+ ensure
75
+ @testno += 1
76
+ end
77
+
78
+ def testing(*args, &block)
79
+ method = ["test", testno, slug_for(*args)].delete_if{|part| part.empty?}.join('_')
80
+ define_method(method, &block)
81
+ end
82
+
83
+ def test(*args, &block)
84
+ testing(*args, &block)
85
+ end
86
+
87
+ def setup(&block)
88
+ define_method(:setup, &block) if block
89
+ end
90
+
91
+ def teardown(&block)
92
+ define_method(:teardown, &block) if block
93
+ end
94
+
95
+ def prepare(&block)
96
+ @prepare ||= []
97
+ @prepare.push(block) if block
98
+ @prepare
99
+ end
100
+
101
+ def cleanup(&block)
102
+ @cleanup ||= []
103
+ @cleanup.push(block) if block
104
+ @cleanup
105
+ end
106
+ end
107
+
108
+ ## configure the subclass!
109
+ #
110
+ const_set(:Testno, '0')
111
+ slug = slug_for(*args).gsub(%r/-/,'_')
112
+ name = ['TESTING', '%03d' % const_get(:Testno), slug].delete_if{|part| part.empty?}.join('_')
113
+ name = name.upcase!
114
+ const_set(:Name, name)
115
+ const_set(:Missing, Object.new.freeze)
116
+
117
+ ## instance methods
118
+ #
119
+ alias_method('__assert__', 'assert')
120
+
121
+ def assert(*args, &block)
122
+ if args.size == 1 and args.first.is_a?(Hash)
123
+ options = args.first
124
+ expected = getopt(:expected, options){ missing }
125
+ actual = getopt(:actual, options){ missing }
126
+ if expected == missing and actual == missing
127
+ actual, expected, *ignored = options.to_a.flatten
128
+ end
129
+ expected = expected.call() if expected.respond_to?(:call)
130
+ actual = actual.call() if actual.respond_to?(:call)
131
+ assert_equal(expected, actual)
132
+ end
133
+
134
+ if block
135
+ label = "assert(#{ args.join(' ') })"
136
+ result = nil
137
+ assert_nothing_raised{ result = block.call }
138
+ __assert__(result, label)
139
+ result
140
+ else
141
+ result = args.shift
142
+ label = "assert(#{ args.join(' ') })"
143
+ __assert__(result, label)
144
+ result
145
+ end
146
+ end
147
+
148
+ def missing
149
+ self.class.const_get(:Missing)
150
+ end
151
+
152
+ def getopt(opt, hash, options = nil, &block)
153
+ [opt.to_s, opt.to_s.to_sym].each do |key|
154
+ return hash[key] if hash.has_key?(key)
155
+ end
156
+ default =
157
+ if block
158
+ block.call
159
+ else
160
+ options.is_a?(Hash) ? options[:default] : nil
161
+ end
162
+ return default
163
+ end
164
+
165
+ def subclass_of exception
166
+ class << exception
167
+ def ==(other) super or self > other end
168
+ end
169
+ exception
170
+ end
171
+
172
+ ##
173
+ #
174
+ module_eval(&block)
175
+
176
+ self.setup()
177
+ self.prepare.each{|b| b.call()}
178
+
179
+ at_exit{
180
+ self.teardown()
181
+ self.cleanup.each{|b| b.call()}
182
+ }
183
+
184
+ self
185
+ end
186
+ end
187
+
188
+
189
+ if $0 == __FILE__
190
+
191
+ Testing 'Testing' do
192
+ testing('foo'){ assert true }
193
+ test{ assert true }
194
+ p instance_methods.grep(/test/)
195
+ end
196
+
197
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_errors2html
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ara T. Howard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: map
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 6.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 6.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rails_view
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.1
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.1
46
+ description: <%= form_for @post do %> <%= @post.errors.to_html %>
47
+ email: ara.t.howard@gmail.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - README.md
53
+ - Rakefile
54
+ - lib/rails_errors2html.rb
55
+ - rails_errors2html.gemspec
56
+ - test/rails_errors2html_test.rb
57
+ - test/testing.rb
58
+ homepage: https://github.com/ahoward/rails_errors2html
59
+ licenses: []
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project: codeforpeople
78
+ rubygems_version: 1.8.24
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: rails_errors2html
82
+ test_files: []