ohm-contrib 0.0.19 → 0.0.20
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/ohm/contrib/typecast.rb +104 -13
- data/lib/ohm/contrib/web_validations.rb +22 -6
- data/lib/ohm/contrib.rb +1 -1
- data/ohm-contrib.gemspec +2 -2
- data/test/test_ohm_typecast.rb +229 -2
- data/test/test_ohm_web_validations.rb +7 -6
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.20
|
data/lib/ohm/contrib/typecast.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'bigdecimal'
|
2
2
|
require 'time'
|
3
3
|
require 'date'
|
4
|
+
require 'json'
|
5
|
+
require 'forwardable'
|
4
6
|
|
5
7
|
module Ohm
|
6
8
|
# Provides all the primitive types. The following are included:
|
@@ -11,6 +13,8 @@ module Ohm
|
|
11
13
|
# * Float
|
12
14
|
# * Date
|
13
15
|
# * Time
|
16
|
+
# * Hash
|
17
|
+
# * Array
|
14
18
|
module Types
|
15
19
|
def self.defined?(type)
|
16
20
|
@constants ||= constants.map(&:to_s)
|
@@ -20,8 +24,35 @@ module Ohm
|
|
20
24
|
def self.[](type)
|
21
25
|
const_get(type.to_s.split('::').last)
|
22
26
|
end
|
27
|
+
|
28
|
+
class Base < BasicObject
|
29
|
+
class Exception < ::Exception; end
|
23
30
|
|
24
|
-
|
31
|
+
extend ::Forwardable
|
32
|
+
|
33
|
+
@@delegation_blacklist = [
|
34
|
+
:==, :to_s, :initialize, :inspect, :object_id, :__send__, :__id__
|
35
|
+
]
|
36
|
+
|
37
|
+
def self.[](value)
|
38
|
+
return self::EMPTY if value.to_s.empty?
|
39
|
+
|
40
|
+
new(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.delegate_to(klass, except = @@delegation_blacklist)
|
44
|
+
methods = klass.public_instance_methods.map(&:to_sym) - except
|
45
|
+
def_delegators :object, *methods
|
46
|
+
end
|
47
|
+
|
48
|
+
def inspect
|
49
|
+
object.inspect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Primitive < Base
|
54
|
+
EMPTY = nil
|
55
|
+
|
25
56
|
def initialize(value)
|
26
57
|
@raw = value
|
27
58
|
end
|
@@ -30,28 +61,23 @@ module Ohm
|
|
30
61
|
@raw.to_s
|
31
62
|
end
|
32
63
|
|
33
|
-
def inspect
|
34
|
-
object
|
35
|
-
end
|
36
|
-
|
37
64
|
def ==(other)
|
38
65
|
to_s == other.to_s
|
39
66
|
end
|
40
|
-
|
67
|
+
|
41
68
|
protected
|
42
69
|
def object
|
43
70
|
@raw
|
44
71
|
end
|
45
|
-
|
46
|
-
def method_missing(meth, *args, &blk)
|
47
|
-
object.send(meth, *args, &blk)
|
48
|
-
end
|
49
72
|
end
|
50
73
|
|
51
74
|
class String < Primitive
|
75
|
+
delegate_to ::String
|
52
76
|
end
|
53
77
|
|
54
78
|
class Decimal < Primitive
|
79
|
+
delegate_to ::BigDecimal
|
80
|
+
|
55
81
|
def inspect
|
56
82
|
object.to_s('F')
|
57
83
|
end
|
@@ -63,6 +89,8 @@ module Ohm
|
|
63
89
|
end
|
64
90
|
|
65
91
|
class Integer < Primitive
|
92
|
+
delegate_to ::Fixnum
|
93
|
+
|
66
94
|
protected
|
67
95
|
def object
|
68
96
|
::Kernel::Integer(@raw)
|
@@ -70,6 +98,8 @@ module Ohm
|
|
70
98
|
end
|
71
99
|
|
72
100
|
class Float < Primitive
|
101
|
+
delegate_to ::Float
|
102
|
+
|
73
103
|
protected
|
74
104
|
def object
|
75
105
|
::Kernel::Float(@raw)
|
@@ -77,6 +107,8 @@ module Ohm
|
|
77
107
|
end
|
78
108
|
|
79
109
|
class Time < Primitive
|
110
|
+
delegate_to ::Time
|
111
|
+
|
80
112
|
protected
|
81
113
|
def object
|
82
114
|
::Time.parse(@raw)
|
@@ -84,11 +116,62 @@ module Ohm
|
|
84
116
|
end
|
85
117
|
|
86
118
|
class Date < Primitive
|
119
|
+
delegate_to ::Date
|
120
|
+
|
87
121
|
protected
|
88
122
|
def object
|
89
123
|
::Date.parse(@raw)
|
90
124
|
end
|
91
125
|
end
|
126
|
+
|
127
|
+
class Serialized < Base
|
128
|
+
attr :object
|
129
|
+
|
130
|
+
def initialize(raw)
|
131
|
+
@object = case raw
|
132
|
+
when self.class::RAW then raw
|
133
|
+
when ::String then ::JSON.parse(raw)
|
134
|
+
when self.class then raw.object
|
135
|
+
else
|
136
|
+
::Kernel.raise ::TypeError,
|
137
|
+
"%s does not accept %s" % [self.class, raw.inspect]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def ==(other)
|
142
|
+
object == other
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_s
|
146
|
+
object.to_json
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Hash < Serialized
|
151
|
+
EMPTY = {}
|
152
|
+
RAW = ::Hash
|
153
|
+
|
154
|
+
delegate_to ::Hash
|
155
|
+
|
156
|
+
# @private since basic object doesn't include a #class we need
|
157
|
+
# to define this manually
|
158
|
+
def class
|
159
|
+
::Ohm::Types::Hash
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class Array < Serialized
|
164
|
+
EMPTY = []
|
165
|
+
RAW = ::Array
|
166
|
+
|
167
|
+
delegate_to ::Array
|
168
|
+
|
169
|
+
# @private since basic object doesn't include a #class we need
|
170
|
+
# to define this manually
|
171
|
+
def class
|
172
|
+
::Ohm::Types::Array
|
173
|
+
end
|
174
|
+
end
|
92
175
|
end
|
93
176
|
|
94
177
|
# Provides unobtrusive, non-explosive typecasting.Instead of exploding on set
|
@@ -184,12 +267,20 @@ module Ohm
|
|
184
267
|
# @return [nil] if the attribute is already defined.
|
185
268
|
def attribute(name, type = Ohm::Types::String, klass = Ohm::Types[type])
|
186
269
|
define_method(name) do
|
187
|
-
|
188
|
-
|
270
|
+
# Primitive types maintain a reference to the original object
|
271
|
+
# stored in @_attributes[att]. Hence mutation works for the
|
272
|
+
# Primitive case. For cases like Hash, Array where the value
|
273
|
+
# is `JSON.parse`d, we need to set the actual Ohm::Types::Hash
|
274
|
+
# (or similar) to @_attributes[att] for mutation to work.
|
275
|
+
if klass.superclass == Ohm::Types::Primitive
|
276
|
+
klass[read_local(name)]
|
277
|
+
else
|
278
|
+
write_local(name, klass[read_local(name)])
|
279
|
+
end
|
189
280
|
end
|
190
281
|
|
191
282
|
define_method(:"#{name}=") do |value|
|
192
|
-
write_local(name, value
|
283
|
+
write_local(name, klass[value].to_s)
|
193
284
|
end
|
194
285
|
|
195
286
|
attributes << name unless attributes.include?(name)
|
@@ -1,35 +1,51 @@
|
|
1
1
|
module Ohm
|
2
2
|
# All credit goes to gnrfan of github
|
3
3
|
# Basically an extraction from http://github.com/gnrfan/ohm_extra_validations
|
4
|
+
#
|
5
|
+
# * 2010-05-29 Updated Email Regex, Extracted out regexs to constants
|
6
|
+
#
|
7
|
+
# This module provides the following:
|
8
|
+
# * assert_slug
|
9
|
+
# * assert_email
|
10
|
+
# * assert_url
|
11
|
+
# * assert_ipv4
|
4
12
|
module WebValidations
|
13
|
+
# @see http://fightingforalostcause.net/misc/2006/compare-email-regex.php
|
14
|
+
EMAIL_REGEX = /^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i
|
15
|
+
|
16
|
+
SLUG_REGEX = /^[-\w]+$/
|
17
|
+
|
18
|
+
URL_REGEX = /^(http|https):\/\/([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}|(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|localhost)(:[0-9]{1,5})?(\/.*)?$/ix
|
19
|
+
|
20
|
+
IPV4_REGEX = /^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$/
|
5
21
|
|
6
22
|
protected
|
7
23
|
def assert_slug(att, error = [att, :not_slug])
|
8
24
|
if assert_present(att, error) and assert_unique(att)
|
9
|
-
|
25
|
+
assert_format(att, SLUG_REGEX, error)
|
10
26
|
end
|
11
27
|
end
|
12
28
|
|
13
29
|
def assert_email(att, error = [att, :not_email])
|
14
30
|
if assert_present(att, error)
|
15
|
-
assert_format(att,
|
31
|
+
assert_format(att, EMAIL_REGEX, error)
|
16
32
|
end
|
17
33
|
end
|
18
34
|
|
19
35
|
def assert_url(att, error = [att, :not_url])
|
20
36
|
if assert_present(att, error)
|
21
|
-
assert_format(att,
|
37
|
+
assert_format(att, URL_REGEX, error)
|
22
38
|
end
|
23
39
|
end
|
24
40
|
|
25
41
|
def assert_ipv4(att, error = [att, :not_ipv4])
|
26
42
|
if assert_present(att, error)
|
27
|
-
assert_format(att,
|
43
|
+
assert_format(att, IPV4_REGEX, error)
|
28
44
|
end
|
29
45
|
end
|
30
46
|
|
31
47
|
def assert_ipaddr(att, error = [att, :not_ipaddr])
|
32
|
-
|
48
|
+
assert_ipv4(att, error)
|
33
49
|
end
|
34
50
|
end
|
35
|
-
end
|
51
|
+
end
|
data/lib/ohm/contrib.rb
CHANGED
data/ohm-contrib.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ohm-contrib}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.20"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Cyril David"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-29}
|
13
13
|
s.description = %q{Highly decoupled drop-in functionality for Ohm models}
|
14
14
|
s.email = %q{cyx.ucron@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/test_ohm_typecast.rb
CHANGED
@@ -145,7 +145,7 @@ class TestOhmTypecast < Test::Unit::TestCase
|
|
145
145
|
|
146
146
|
test "inspecting" do
|
147
147
|
post = Post.new(:price => "50000")
|
148
|
-
assert_equal 50000, post.price.inspect
|
148
|
+
assert_equal '50000', post.price.inspect
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
@@ -191,7 +191,7 @@ class TestOhmTypecast < Test::Unit::TestCase
|
|
191
191
|
|
192
192
|
test "inspecting" do
|
193
193
|
post = Post.new(:price => "12345.67890")
|
194
|
-
assert_equal 12345.
|
194
|
+
assert_equal '12345.6789', post.price.inspect
|
195
195
|
end
|
196
196
|
end
|
197
197
|
|
@@ -318,4 +318,231 @@ class TestOhmTypecast < Test::Unit::TestCase
|
|
318
318
|
assert_equal Date.today, Post.new.today
|
319
319
|
end
|
320
320
|
end
|
321
|
+
|
322
|
+
context "when using a Hash" do
|
323
|
+
class Post < Ohm::Model
|
324
|
+
include Ohm::Typecast
|
325
|
+
|
326
|
+
attribute :address, Hash
|
327
|
+
|
328
|
+
def hash
|
329
|
+
Hash.new
|
330
|
+
end
|
331
|
+
|
332
|
+
def top_level_hash
|
333
|
+
Hash
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
test "importing" do
|
338
|
+
assert_equal Hash.new, Ohm::Types::Hash[nil]
|
339
|
+
assert_equal Hash.new, Ohm::Types::Hash[""]
|
340
|
+
assert_equal Hash.new, Ohm::Types::Hash[{}]
|
341
|
+
|
342
|
+
assert_equal Hash[:a => "b", :c => "d"],
|
343
|
+
Ohm::Types::Hash[{ :a => "b", :c => "d" }]
|
344
|
+
end
|
345
|
+
|
346
|
+
test "exporting / dumping" do
|
347
|
+
assert_equal "{}", Ohm::Types::Hash[nil].to_s
|
348
|
+
assert_equal "{}", Ohm::Types::Hash[""].to_s
|
349
|
+
assert_equal "{}", Ohm::Types::Hash[{}].to_s
|
350
|
+
|
351
|
+
assert_equal %q{{"a":"b","c":"d"}},
|
352
|
+
Ohm::Types::Hash[{ :a => "b", :c => "d" }].to_s
|
353
|
+
end
|
354
|
+
|
355
|
+
test "still able to get top level methods" do
|
356
|
+
assert_equal({}, Post.new.hash)
|
357
|
+
assert_equal Hash, Post.new.top_level_hash
|
358
|
+
end
|
359
|
+
|
360
|
+
test "handles nil case correctly" do
|
361
|
+
post = Post.create(:address => nil)
|
362
|
+
assert_equal({}, post.address)
|
363
|
+
|
364
|
+
post = Post[post.id]
|
365
|
+
assert_equal({}, post.address)
|
366
|
+
end
|
367
|
+
|
368
|
+
test "handles empty string case correctly" do
|
369
|
+
post = Post.create(:address => "")
|
370
|
+
assert_equal({}, post.address)
|
371
|
+
|
372
|
+
post = Post[post.id]
|
373
|
+
assert_equal({}, post.address)
|
374
|
+
end
|
375
|
+
|
376
|
+
test "handles populated hashes" do
|
377
|
+
address = { "address1" => "#123", "city" => "Singapore", "country" => "SG"}
|
378
|
+
post = Post.create(:address => address)
|
379
|
+
assert_equal address, post.address
|
380
|
+
|
381
|
+
post = Post[post.id]
|
382
|
+
assert_equal address, post.address
|
383
|
+
end
|
384
|
+
|
385
|
+
test "allows for hash operations" do
|
386
|
+
address = { "address1" => "#123", "city" => "Singapore", "country" => "SG"}
|
387
|
+
post = Post.create(:address => address)
|
388
|
+
|
389
|
+
assert_equal ["address1", "city", "country"], post.address.keys
|
390
|
+
assert_equal ["#123", "Singapore", "SG"], post.address.values
|
391
|
+
|
392
|
+
post = Post[post.id]
|
393
|
+
assert_equal ["address1", "city", "country"], post.address.keys
|
394
|
+
assert_equal ["#123", "Singapore", "SG"], post.address.values
|
395
|
+
end
|
396
|
+
|
397
|
+
test "handles mutation" do
|
398
|
+
address = { "address1" => "#123", "city" => "Singapore", "country" => "SG"}
|
399
|
+
post = Post.create(:address => address)
|
400
|
+
|
401
|
+
post.address["address1"] = "#456"
|
402
|
+
post.save
|
403
|
+
|
404
|
+
assert_equal ["address1", "city", "country"], post.address.keys
|
405
|
+
assert_equal ["#456", "Singapore", "SG"], post.address.values
|
406
|
+
|
407
|
+
post = Post[post.id]
|
408
|
+
assert_equal ["address1", "city", "country"], post.address.keys
|
409
|
+
assert_equal ["#456", "Singapore", "SG"], post.address.values
|
410
|
+
end
|
411
|
+
|
412
|
+
Address = Class.new(Struct.new(:city, :country))
|
413
|
+
|
414
|
+
test "raises when trying to assign a non-hash" do
|
415
|
+
assert_raise TypeError do
|
416
|
+
Post.new(:address => [])
|
417
|
+
end
|
418
|
+
|
419
|
+
assert_raise TypeError do
|
420
|
+
Post.new(:address => Address.new)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
context "when using an Array" do
|
426
|
+
class Post < Ohm::Model
|
427
|
+
include Ohm::Typecast
|
428
|
+
|
429
|
+
attribute :addresses, Array
|
430
|
+
|
431
|
+
def array
|
432
|
+
Array.new
|
433
|
+
end
|
434
|
+
|
435
|
+
def top_level_array
|
436
|
+
Array
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
test "importing" do
|
441
|
+
assert_equal [], Ohm::Types::Array[nil]
|
442
|
+
assert_equal [], Ohm::Types::Array[""]
|
443
|
+
assert_equal [], Ohm::Types::Array[[]]
|
444
|
+
|
445
|
+
assert_equal ['a', 'b', 'c', 'd'],
|
446
|
+
Ohm::Types::Array[['a', 'b', 'c', 'd']]
|
447
|
+
end
|
448
|
+
|
449
|
+
test "exporting / dumping" do
|
450
|
+
assert_equal "[]", Ohm::Types::Array[nil].to_s
|
451
|
+
assert_equal "[]", Ohm::Types::Array[""].to_s
|
452
|
+
assert_equal "[]", Ohm::Types::Array[[]].to_s
|
453
|
+
|
454
|
+
assert_equal %q{["a","b","c","d"]},
|
455
|
+
Ohm::Types::Array[['a', 'b', 'c', 'd']].to_s
|
456
|
+
end
|
457
|
+
|
458
|
+
test "still able to get top level methods" do
|
459
|
+
assert_equal([], Post.new.array)
|
460
|
+
assert_equal Array, Post.new.top_level_array
|
461
|
+
end
|
462
|
+
|
463
|
+
test "handles nil case correctly" do
|
464
|
+
post = Post.create(:addresses => nil)
|
465
|
+
assert_equal([], post.addresses)
|
466
|
+
|
467
|
+
post = Post[post.id]
|
468
|
+
assert_equal([], post.addresses)
|
469
|
+
end
|
470
|
+
|
471
|
+
test "handles empty string case correctly" do
|
472
|
+
post = Post.create(:addresses => "")
|
473
|
+
assert_equal([], post.addresses)
|
474
|
+
|
475
|
+
post = Post[post.id]
|
476
|
+
assert_equal([], post.addresses)
|
477
|
+
end
|
478
|
+
|
479
|
+
test "handles populated arrays" do
|
480
|
+
addresses = [{"city" => "Singapore", "country" => "SG"},
|
481
|
+
{"city" => "Manila", "country" => "PH"}]
|
482
|
+
|
483
|
+
post = Post.create(:addresses => addresses)
|
484
|
+
assert_equal addresses, post.addresses
|
485
|
+
|
486
|
+
post = Post[post.id]
|
487
|
+
assert_equal addresses, post.addresses
|
488
|
+
end
|
489
|
+
|
490
|
+
class Address < Struct.new(:city, :country)
|
491
|
+
def to_json
|
492
|
+
[city, country].to_json
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
test "handles an arbitrary class as an element of the array" do
|
497
|
+
addresses = [Address.new("Singapore", "SG"),
|
498
|
+
Address.new("Philippines", "PH")]
|
499
|
+
|
500
|
+
post = Post.create(:addresses => addresses)
|
501
|
+
assert_equal [['Singapore', 'SG'], ['Philippines', 'PH']], post.addresses
|
502
|
+
|
503
|
+
post = Post[post.id]
|
504
|
+
assert_equal [['Singapore', 'SG'], ['Philippines', 'PH']], post.addresses
|
505
|
+
end
|
506
|
+
|
507
|
+
test "allows for array operations" do
|
508
|
+
addresses = [{"city" => "Singapore", "country" => "SG"},
|
509
|
+
{"city" => "Manila", "country" => "PH"}]
|
510
|
+
|
511
|
+
|
512
|
+
post = Post.create(:addresses => addresses)
|
513
|
+
assert_equal 2, post.addresses.size
|
514
|
+
assert_equal addresses + [{"city" => "Hong Kong", "country" => "ZN"}],
|
515
|
+
post.addresses.push({"city" => "Hong Kong", "country" => "ZN"})
|
516
|
+
|
517
|
+
post = Post[post.id]
|
518
|
+
assert_equal 2, post.addresses.size
|
519
|
+
assert_equal addresses + [{"city" => "Hong Kong", "country" => "ZN"}],
|
520
|
+
post.addresses.push({"city" => "Hong Kong", "country" => "ZN"})
|
521
|
+
end
|
522
|
+
|
523
|
+
test "handles mutation" do
|
524
|
+
post = Post.create(:addresses => [1, 2, 3])
|
525
|
+
|
526
|
+
post.addresses.push(4, 5, 6)
|
527
|
+
post.save
|
528
|
+
|
529
|
+
assert_equal 6, post.addresses.size
|
530
|
+
assert_equal [1, 2, 3, 4, 5, 6], post.addresses
|
531
|
+
|
532
|
+
post = Post[post.id]
|
533
|
+
assert_equal 6, post.addresses.size
|
534
|
+
assert_equal [1, 2, 3, 4, 5, 6], post.addresses
|
535
|
+
end
|
536
|
+
|
537
|
+
|
538
|
+
test "raises when trying to assign a non-array" do
|
539
|
+
assert_raise TypeError do
|
540
|
+
Post.new(:addresses => {})
|
541
|
+
end
|
542
|
+
|
543
|
+
assert_raise TypeError do
|
544
|
+
Post.new(:addresses => Address.new)
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
321
548
|
end
|
@@ -29,6 +29,7 @@ class TestOhmWebValidations < Test::Unit::TestCase
|
|
29
29
|
|
30
30
|
context "The slug should be valid" do
|
31
31
|
def setup
|
32
|
+
Ohm.flush
|
32
33
|
@blog_post_01 = BlogPost.new
|
33
34
|
@blog_post_02 = BlogPost.new
|
34
35
|
end
|
@@ -41,11 +42,11 @@ class TestOhmWebValidations < Test::Unit::TestCase
|
|
41
42
|
assert_equal [[:slug, :not_slug]], @blog_post_01.errors
|
42
43
|
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
should "succeed if the slug is valid" do
|
46
|
+
@blog_post_02.slug = "this-is-a-valid-slug"
|
47
|
+
@blog_post_02.create
|
48
|
+
assert_not_nil @blog_post_02.id
|
49
|
+
end
|
49
50
|
|
50
51
|
should "fail if the slug is not unique" do
|
51
52
|
|
@@ -110,4 +111,4 @@ class TestOhmWebValidations < Test::Unit::TestCase
|
|
110
111
|
end
|
111
112
|
|
112
113
|
end
|
113
|
-
end
|
114
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 20
|
9
|
+
version: 0.0.20
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Cyril David
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-29 00:00:00 +08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|