nitro 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/AUTHORS +14 -4
  2. data/ChangeLog +192 -1
  3. data/README +50 -6
  4. data/RELEASES +60 -0
  5. data/Rakefile +1 -1
  6. data/bin/cluster.rb +2 -2
  7. data/bin/new_form.rb +1 -1
  8. data/examples/blog/config.rb +5 -4
  9. data/examples/blog/lib/blog.rb +56 -36
  10. data/examples/blog/root/comments.xhtml +5 -2
  11. data/examples/blog/root/entry_form.xhtml +7 -2
  12. data/examples/blog/root/login.xhtml +1 -1
  13. data/examples/blog/root/style.xsl +7 -0
  14. data/examples/og/mock_example.rb +6 -9
  15. data/examples/og/mysql_to_psql.rb +100 -0
  16. data/examples/og/run.rb +8 -17
  17. data/lib/glue.rb +7 -8
  18. data/lib/glue/array.rb +1 -1
  19. data/lib/glue/attribute.rb +86 -0
  20. data/lib/glue/cache.rb +1 -1
  21. data/lib/glue/hash.rb +1 -1
  22. data/lib/glue/inflector.rb +1 -1
  23. data/lib/glue/logger.rb +118 -18
  24. data/lib/glue/mixins.rb +1 -1
  25. data/lib/glue/number.rb +1 -1
  26. data/lib/glue/pool.rb +1 -1
  27. data/lib/glue/property.rb +48 -31
  28. data/lib/glue/string.rb +1 -1
  29. data/lib/glue/time.rb +2 -2
  30. data/lib/glue/validation.rb +400 -0
  31. data/lib/nitro/application.rb +6 -6
  32. data/lib/nitro/builders/form.rb +5 -5
  33. data/lib/nitro/builders/rss.rb +1 -1
  34. data/lib/nitro/builders/xhtml.rb +119 -0
  35. data/lib/nitro/builders/xml.rb +111 -0
  36. data/lib/nitro/config.rb +6 -6
  37. data/lib/nitro/events.rb +1 -1
  38. data/lib/nitro/html.rb +1 -1
  39. data/lib/nitro/markup.rb +15 -20
  40. data/lib/nitro/scaffold.rb +2 -2
  41. data/lib/nitro/server/appserver.rb +3 -3
  42. data/lib/nitro/server/cluster.rb +2 -2
  43. data/lib/nitro/server/dispatcher.rb +2 -2
  44. data/lib/nitro/server/filters/autologin.rb +1 -1
  45. data/lib/nitro/server/fragment.rb +2 -2
  46. data/lib/nitro/server/handlers.rb +2 -2
  47. data/lib/nitro/server/render.rb +17 -15
  48. data/lib/nitro/server/request.rb +6 -6
  49. data/lib/nitro/server/script.rb +2 -2
  50. data/lib/nitro/server/server.rb +2 -2
  51. data/lib/nitro/server/session.rb +6 -6
  52. data/lib/nitro/server/shaders.rb +2 -2
  53. data/lib/nitro/server/webrick.rb +1 -1
  54. data/lib/nitro/sitemap.rb +2 -2
  55. data/lib/nitro/uri.rb +1 -1
  56. data/lib/nitro/version.rb +7 -5
  57. data/lib/og.rb +95 -129
  58. data/lib/og/backend.rb +47 -46
  59. data/lib/og/backends/mysql.rb +64 -63
  60. data/lib/og/backends/psql.rb +73 -72
  61. data/lib/og/connection.rb +7 -8
  62. data/lib/og/enchant.rb +80 -0
  63. data/lib/og/meta.rb +21 -21
  64. data/lib/og/mock.rb +31 -88
  65. data/lib/og/version.rb +6 -5
  66. data/lib/parts/README +9 -0
  67. data/lib/parts/content.rb +23 -9
  68. data/test/glue/tc_attribute.rb +22 -0
  69. data/test/glue/tc_cache.rb +4 -6
  70. data/test/glue/tc_hash.rb +2 -2
  71. data/test/glue/tc_logger.rb +36 -0
  72. data/test/glue/tc_numbers.rb +2 -2
  73. data/test/glue/tc_property_mixins.rb +35 -4
  74. data/test/glue/tc_strings.rb +32 -32
  75. data/test/glue/tc_validation.rb +186 -0
  76. data/test/nitro/builders/tc_xhtml.rb +38 -0
  77. data/test/nitro/builders/tc_xml.rb +47 -0
  78. data/test/nitro/server/tc_request.rb +2 -2
  79. data/test/nitro/server/tc_session.rb +1 -1
  80. data/test/nitro/tc_sitemap.rb +1 -1
  81. data/test/nitro/ui/tc_pager.rb +1 -10
  82. data/test/tc_og.rb +3 -3
  83. data/vendor/blankslate.rb +53 -0
  84. data/vendor/extensions/_base.rb +153 -0
  85. data/vendor/extensions/_template.rb +36 -0
  86. data/vendor/extensions/all.rb +21 -0
  87. data/vendor/extensions/array.rb +68 -0
  88. data/vendor/extensions/binding.rb +224 -0
  89. data/vendor/extensions/class.rb +50 -0
  90. data/vendor/extensions/continuation.rb +71 -0
  91. data/vendor/extensions/enumerable.rb +250 -0
  92. data/vendor/extensions/hash.rb +23 -0
  93. data/vendor/extensions/io.rb +58 -0
  94. data/vendor/extensions/kernel.rb +42 -0
  95. data/vendor/extensions/module.rb +114 -0
  96. data/vendor/extensions/numeric.rb +230 -0
  97. data/vendor/extensions/object.rb +164 -0
  98. data/vendor/extensions/ostruct.rb +41 -0
  99. data/vendor/extensions/string.rb +316 -0
  100. data/vendor/extensions/symbol.rb +28 -0
  101. metadata +35 -13
  102. data/lib/glue/property.rb.old +0 -307
@@ -0,0 +1,9 @@
1
+ = Parts
2
+
3
+ Parts are 'modules of functionality'. This is a higher level concept.
4
+ Examples of parts could be a Forum, a Content/User management system,
5
+ etc.
6
+
7
+ Nitro is a low level framework and does not include functionality parts
8
+ in the standard distribution. Libraries of modules will be available from
9
+ Navel and other vendors.
@@ -1,10 +1,8 @@
1
- # = Content
2
- #
3
- # Content Management Foundation
1
+ # = Content
4
2
  #
5
- # code:
6
- # * George Moschovitis <gm@navel.gr>
3
+ # Content management foundation.
7
4
  #
5
+ # George Moschovitis <gm@navel.gr>
8
6
  # (c) 2004 Navel, all rights reserved.
9
7
  # $Id$
10
8
 
@@ -23,15 +21,31 @@ module BaseContent
23
21
  prop_accessor :body, String, :markup => true, :ui => :textarea
24
22
  end
25
23
 
24
+ # = CreateTime mixin.
25
+ #
26
+ module CreateTime
27
+ prop_accessor :create_time, Time
28
+ prop_accessor :update_time, Time
29
+
30
+ def og_pre_insert(conn)
31
+ @create_time = @update_time = Time.now
32
+ end
33
+
34
+ def og_pre_update(conn)
35
+ @update_time = Time.now
36
+ end
37
+ end
38
+
26
39
  # = Content
27
40
  #
28
41
  # The foundamental Content Unit.
29
- #
30
42
  #--
31
43
  # THINK: rename this to Entity?
32
44
  #++
45
+
33
46
  module Content
34
47
  include N::BaseContent
48
+ prop_accessor :name, String
35
49
  prop_accessor :ctime, Time
36
50
  prop_accessor :mtime, Time
37
51
 
@@ -41,7 +55,7 @@ module Content
41
55
  end
42
56
 
43
57
  # = Category
44
- #
58
+
45
59
  class Category
46
60
  include N::BaseContent
47
61
  end
@@ -49,7 +63,7 @@ end
49
63
  # = ACL
50
64
  #
51
65
  # Unix style permissions.
52
- #
66
+
53
67
  module ACL
54
68
  # bits:
55
69
  # 0, 1, 2: owner read, write, execute
@@ -58,4 +72,4 @@ module ACL
58
72
  prop_accessor :permissions
59
73
  end
60
74
 
61
- end # module
75
+ end
@@ -0,0 +1,22 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ require 'test/unit'
4
+ require 'glue/attribute'
5
+
6
+ class TC_Attribute < Test::Unit::TestCase # :nodoc: all
7
+
8
+ class Dummy
9
+ cattr_accessor :value, 'Default'
10
+ cattr_reader :reader, 3
11
+ end
12
+
13
+ def test_attr
14
+ assert_equal 'Default', Dummy.value
15
+ assert_nothing_raised { Dummy.value = 2 }
16
+ assert_equal 2, Dummy.value
17
+
18
+ assert_equal 3, Dummy.reader
19
+ assert_raise(NoMethodError) { Dummy.reader = 19 }
20
+ end
21
+
22
+ end
@@ -1,17 +1,15 @@
1
- # :nodoc: all
2
-
3
1
  require "test/unit"
4
2
  require "glue/cache"
5
3
 
6
- class TC_N_Utils_Cache < Test::Unit::TestCase
4
+ class TC_Glue_Cache < Test::Unit::TestCase
7
5
  # :nodoc: all
8
6
 
9
7
  class Dummy
10
- include G::LRUCache::Item
8
+ include N::LRUCache::Item
11
9
  end
12
10
 
13
11
  def setup
14
- @cache = G::LRUCache.new(maxitems = 3)
12
+ @cache = N::LRUCache.new(maxitems = 3)
15
13
  end
16
14
 
17
15
  def teardown
@@ -44,4 +42,4 @@ class TC_N_Utils_Cache < Test::Unit::TestCase
44
42
  assert_equal(d4, @cache.first)
45
43
  end
46
44
 
47
- end
45
+ end
@@ -7,7 +7,7 @@ class TC_N2_Utils_Cache < Test::Unit::TestCase
7
7
  # :nodoc: all
8
8
 
9
9
  def setup
10
- @safe_cache = G::SafeHash.new(Hash.new)
10
+ @safe_cache = N::SafeHash.new(Hash.new)
11
11
  end
12
12
 
13
13
  def teardown
@@ -35,4 +35,4 @@ class TC_N2_Utils_Cache < Test::Unit::TestCase
35
35
  assert_equal(3, @safe_cache.values.size)
36
36
  end
37
37
 
38
- end
38
+ end
@@ -0,0 +1,36 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'vendor')
3
+
4
+ require 'stringio'
5
+
6
+ require 'test/unit'
7
+ require 'glue/logger'
8
+
9
+ class TC_Logger < Test::Unit::TestCase # :nodoc: all
10
+
11
+ def setup
12
+ @io = StringIO.new('')
13
+ Logger.set(Logger.new(@io))
14
+ end
15
+
16
+ def test_logger
17
+ Logger.info 'hello'
18
+ assert_equal(" INFO: hello\n", @io.string)
19
+
20
+ # bug: Binding.of_caller thinks Logger is the caller.
21
+ a = 14
22
+ b = 13
23
+ Logger.trace 'a * b'
24
+ assert_equal(" INFO: hello\nDEBUG: a * b = 182\n", @io.string)
25
+
26
+ @io.string = ''
27
+ Logger.debug 'hello'
28
+ assert_equal("DEBUG: hello\n", @io.string)
29
+
30
+ # test logging level.
31
+ Logger.get.level = Logger::INFO
32
+ Logger.debug 'world'
33
+ assert_equal("DEBUG: hello\n", @io.string)
34
+ end
35
+
36
+ end
@@ -13,8 +13,8 @@ class TC_N_NumberUtils < Test::Unit::TestCase
13
13
  end
14
14
 
15
15
  def test_ceil_multiple
16
- assert_equal(20, G::NumberUtils.ceil_multiple(15, 10))
17
- assert_equal(10, G::NumberUtils.ceil_multiple(1, 10))
16
+ assert_equal(20, N::NumberUtils.ceil_multiple(15, 10))
17
+ assert_equal(10, N::NumberUtils.ceil_multiple(1, 10))
18
18
  end
19
19
 
20
20
  end
@@ -1,11 +1,11 @@
1
1
  #! /usr/bin/env ruby
2
2
  # vim:sw=2:ai
3
3
 
4
- # code:
5
- # * Thomas Quas <tquas@yahoo.com>
6
- # * George Moschovitis <gm@navel.gr>
7
- #
4
+ #--
5
+ # Thomas Quas <tquas@yahoo.com>
6
+ # George Moschovitis <gm@navel.gr>
8
7
  # $Id$
8
+ #++
9
9
 
10
10
  $LOAD_PATH.unshift 'lib'
11
11
 
@@ -14,9 +14,16 @@ require 'glue/property'
14
14
 
15
15
  module Mixin
16
16
  prop_accessor :date
17
+ meta :dummy, [123]
17
18
  end
18
19
 
19
20
  class MixedOnly
21
+ include Mixin
22
+ __meta[:dummy] << 5
23
+ __meta[:dummy] << 3
24
+ end
25
+
26
+ class MixedOnly2
20
27
  include Mixin
21
28
  end
22
29
 
@@ -33,6 +40,18 @@ end
33
40
  class Empty
34
41
  end
35
42
 
43
+ class Base
44
+ prop_accessor :date
45
+ meta :dummy, [123]
46
+ end
47
+
48
+ class Child1 < Base
49
+ __meta[:dummy].first << 5
50
+ __meta[:dummy].first << 3
51
+ end
52
+
53
+ class Child2 < Base
54
+ end
36
55
 
37
56
  # Tests auto management.
38
57
  class TC_MixinsTest < ::Test::Unit::TestCase
@@ -59,4 +78,16 @@ class TC_MixinsTest < ::Test::Unit::TestCase
59
78
  assert( obj.respond_to?( :date ) )
60
79
  assert( obj.respond_to?( :dummy ) )
61
80
  end
81
+
82
+ def test_crosspolination
83
+ assert_equal 3, MixedOnly.__meta[:dummy].size
84
+ assert_equal 1, MixedOnly2.__meta[:dummy].size
85
+ assert_equal 1, Mixin.__meta[:dummy].size
86
+ =begin
87
+ gmosx: THINK!
88
+ assert_equal 3, Child1.__meta[:dummy].first.size
89
+ assert_equal 1, Child2.__meta[:dummy].first.size
90
+ assert_equal 1, Base.__meta[:dummy].first.size
91
+ =end
92
+ end
62
93
  end
@@ -11,20 +11,20 @@ class TC_StringUtilsUtils < Test::Unit::TestCase
11
11
  end
12
12
 
13
13
  def test_valid?
14
- assert_equal(true, G::StringUtils.valid?("test"))
15
- assert_equal(false, G::StringUtils.valid?(""))
16
- assert_equal(false, G::StringUtils.valid?(nil))
14
+ assert_equal(true, N::StringUtils.valid?("test"))
15
+ assert_equal(false, N::StringUtils.valid?(""))
16
+ assert_equal(false, N::StringUtils.valid?(nil))
17
17
  end
18
18
 
19
19
  def test_head
20
- assert_equal(nil, G::StringUtils.head(nil))
21
- assert_equal("this...", G::StringUtils.head(@s, 3))
22
- assert_equal("this+++", G::StringUtils.head(@s, 3, false, "+++"))
23
- assert_equal("thi...", G::StringUtils.head(@s, 3, true))
24
- assert_equal("this is...", G::StringUtils.head(@s, 8))
25
- assert_equal(nil, G::StringUtils.head(@s, 0))
26
- assert_equal(nil, G::StringUtils.head(@s, 0, true))
27
- assert_equal("this is...", G::StringUtils.head(@s, 8, true))
20
+ assert_equal(nil, N::StringUtils.head(nil))
21
+ assert_equal("this...", N::StringUtils.head(@s, 3))
22
+ assert_equal("this+++", N::StringUtils.head(@s, 3, false, "+++"))
23
+ assert_equal("thi...", N::StringUtils.head(@s, 3, true))
24
+ assert_equal("this is...", N::StringUtils.head(@s, 8))
25
+ assert_equal(nil, N::StringUtils.head(@s, 0))
26
+ assert_equal(nil, N::StringUtils.head(@s, 0, true))
27
+ assert_equal("this is...", N::StringUtils.head(@s, 8, true))
28
28
  end
29
29
 
30
30
  def test_rewrite
@@ -34,65 +34,65 @@ class TC_StringUtilsUtils < Test::Unit::TestCase
34
34
  [/^games/, "../../games"],
35
35
  [/^tmp/, "/n/theseas/var/tmp"],
36
36
  ]
37
- string = G::StringUtils.rewrite("games/arkanoid.html", rules)
37
+ string = N::StringUtils.rewrite("games/arkanoid.html", rules)
38
38
  assert_equal("../../games/arkanoid.html", string)
39
- string = G::StringUtils.rewrite("tmp/garbage.html", rules)
39
+ string = N::StringUtils.rewrite("tmp/garbage.html", rules)
40
40
  assert_equal("/n/theseas/var/tmp/garbage.html", string)
41
- string = G::StringUtils.rewrite("root/index.html", rules)
41
+ string = N::StringUtils.rewrite("root/index.html", rules)
42
42
  assert_equal("root/index.html", string)
43
- assert_equal(nil, G::StringUtils.rewrite(nil, rules))
44
- assert_equal("", G::StringUtils.rewrite("", rules))
43
+ assert_equal(nil, N::StringUtils.rewrite(nil, rules))
44
+ assert_equal("", N::StringUtils.rewrite("", rules))
45
45
 
46
46
  assert_raises(ArgumentError) {
47
- assert_equal("koko", G::StringUtils.rewrite("koko", nil))
47
+ assert_equal("koko", N::StringUtils.rewrite("koko", nil))
48
48
  }
49
49
 
50
50
  # bug: should keep order
51
- s = G::StringUtils.rewrite("/$/koko.html", rules)
51
+ s = N::StringUtils.rewrite("/$/koko.html", rules)
52
52
  assert_equal("../n1/koko.html", s)
53
53
  end
54
54
 
55
55
  def test_wrap
56
56
  s = "1234567890abcdefghijklmnopqrstu"
57
57
  r = "1234 5678 90ab cdef ghij klmn opqr stu"
58
- assert_equal(r, G::StringUtils::wrap(s, 4, " "))
58
+ assert_equal(r, N::StringUtils::wrap(s, 4, " "))
59
59
 
60
60
  s = "111111111111111111111111111111111111111111111111"
61
61
  r = "1111111111 1111111111 1111111111 1111111111 11111111"
62
- assert_equal(r, G::StringUtils::wrap(s, 10, " "))
62
+ assert_equal(r, N::StringUtils::wrap(s, 10, " "))
63
63
 
64
64
  s = "jackdaws love my big sphinx of quartz"
65
65
  r = "jackdaws love my big sphinx of quartz"
66
- assert_equal(r, G::StringUtils::wrap(s, 10, " "))
66
+ assert_equal(r, N::StringUtils::wrap(s, 10, " "))
67
67
 
68
68
  s = "jackdaws love my big sphinx of quartz"
69
69
  r = "jack daws love my big sphi nx of quar tz"
70
- assert_equal(r, G::StringUtils::wrap(s, 4, " "))
70
+ assert_equal(r, N::StringUtils::wrap(s, 4, " "))
71
71
 
72
72
  s = "jack.daws love my big sphinx of quartz"
73
73
  r = "jack .daw s love my big sphi nx of quar tz"
74
- assert_equal(r, G::StringUtils::wrap(s, 4, " "))
74
+ assert_equal(r, N::StringUtils::wrap(s, 4, " "))
75
75
 
76
- assert_equal("", G::StringUtils::wrap("", 4, " "))
77
- assert_equal(nil, G::StringUtils::wrap(nil, 4, " "))
76
+ assert_equal("", N::StringUtils::wrap("", 4, " "))
77
+ assert_equal(nil, N::StringUtils::wrap(nil, 4, " "))
78
78
  end
79
79
 
80
80
  def test_rationalize_filename
81
- filename = G::StringUtils.rationalize_filename("hello my friend!.gif")
81
+ filename = N::StringUtils.rationalize_filename("hello my friend!.gif")
82
82
  assert_equal("hello-my-friend.gif", filename)
83
- filename = G::StringUtils.rationalize_filename("���� ����.gif")
83
+ filename = N::StringUtils.rationalize_filename("���� ����.gif")
84
84
  assert_equal("pame-pali.gif", filename)
85
- filename = G::StringUtils.rationalize_filename("�� ���.gif")
85
+ filename = N::StringUtils.rationalize_filename("�� ���.gif")
86
86
  assert_equal("ti-les.gif", filename)
87
87
 
88
88
  # bug:
89
- filename = G::StringUtils.rationalize_filename("image-(10).gif")
89
+ filename = N::StringUtils.rationalize_filename("image-(10).gif")
90
90
  assert_equal("image-10.gif", filename)
91
91
  end
92
92
 
93
93
  def test_random_string
94
- s1 = G::StringUtils.random()
95
- s2 = G::StringUtils.random()
94
+ s1 = N::StringUtils.random()
95
+ s2 = N::StringUtils.random()
96
96
  assert_not_equal(s1, s2)
97
97
  assert(s1.size == s2.size)
98
98
  end
@@ -100,4 +100,4 @@ class TC_StringUtilsUtils < Test::Unit::TestCase
100
100
  def teardown
101
101
  @s = nil
102
102
  end
103
- end
103
+ end
@@ -0,0 +1,186 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ require 'test/unit'
4
+
5
+ require 'glue'
6
+ require 'glue/validation'
7
+
8
+ class TC_Validation < Test::Unit::TestCase # :nodoc: all
9
+
10
+ # Override the default error message
11
+ N::Validation::Errors.invalid_format = 'INVALID'
12
+
13
+ module Mixin
14
+ prop_accessor :value, String
15
+ validate_format :value, :format => /123/, :msg => 'mixin error'
16
+ end
17
+
18
+ class User
19
+ include Mixin
20
+
21
+ prop_accessor :name, String
22
+ validate_format :name, :format => /Leo/, :msg => 'per class override'
23
+ end
24
+
25
+ class Article
26
+ prop_accessor :name, String
27
+ validate_format :name, :format => /news/
28
+ end
29
+
30
+ class Dummy1
31
+ prop_accessor :test, Fixnum
32
+ prop_accessor :str, String
33
+ validate_value :test, :str
34
+ end
35
+
36
+ class Dummy2
37
+ prop_accessor :password, String
38
+ validate_confirmation :password
39
+ end
40
+
41
+ class Dummy3
42
+ prop_accessor :vmin, String
43
+ validate_length :vmin, :min => 2
44
+
45
+ prop_accessor :vmax, String
46
+ validate_length :vmax, :max => 3, :msg => 'LOOONG'
47
+
48
+ prop_accessor :vran, String
49
+ validate_length :vran, :range => 2..4, :msg_long => 'argh'
50
+
51
+ prop_accessor :vlen, String
52
+ validate_length :vlen, :length => 3, :msg => 'argh'
53
+ end
54
+
55
+ class Dummy4
56
+ prop_accessor :sex, String
57
+ validate_inclusion :sex, :in => %w{ Male Female }, :msg => 'huh?'
58
+
59
+ prop_accessor :age, Fixnum
60
+ validate_inclusion :age, :in => 5..99
61
+ end
62
+
63
+ # bug
64
+
65
+ class NoProp
66
+ include Mixin
67
+ validate_length :value, :min => 3
68
+ end
69
+
70
+ def test_validate_value
71
+ d = Dummy1.new
72
+
73
+ assert !d.valid?
74
+ assert_equal 2, d.errors.count
75
+ d.test = 1
76
+ assert !d.valid?
77
+ assert_equal 1, d.errors.count
78
+ d.str = 'yeah'
79
+ assert d.valid?
80
+ end
81
+
82
+ def test_validate_confirmation
83
+ d = Dummy2.new
84
+
85
+ assert_respond_to d, :password_confirmation
86
+
87
+ d.password = 'hello'
88
+ assert !d.valid?
89
+ d.password_confirmation = 'hel'
90
+ assert !d.valid?
91
+ d.password_confirmation = 'hello'
92
+ assert d.valid?
93
+ end
94
+
95
+ def test_validate_format
96
+ u = User.new
97
+
98
+ u.value = '1234'
99
+
100
+ u.name = 'George'
101
+ assert !u.valid?
102
+
103
+ assert_equal 'per class override', u.errors[:name].first
104
+
105
+ u.name = 'Leonard'
106
+ assert u.valid?
107
+
108
+ a = Article.new
109
+
110
+ a.name = 'In the news'
111
+ assert a.valid?
112
+
113
+ a.name = 'Sports'
114
+ assert !a.valid?
115
+
116
+ assert_equal 1, a.errors.count
117
+ assert_equal 1, a.errors.on(:name).size
118
+ assert_kind_of Array, a.errors[:name]
119
+
120
+ assert_equal 'INVALID', a.errors[:name].first
121
+
122
+ # test mixin
123
+
124
+ u.value = '543'
125
+ assert !u.valid?
126
+ end
127
+
128
+ def test_validate_length
129
+ d = Dummy3.new
130
+
131
+ d.vmin = 'q'
132
+ d.vmax = '2'
133
+ d.vlen = '123'
134
+ d.vran = '123'
135
+
136
+ assert !d.valid?
137
+ assert_equal 'Too short, must be more than 2 characters long', d.errors.on(:vmin).first
138
+ d.vmin = 'longer'
139
+ assert d.valid?
140
+
141
+ d.vmax = 'loooooooooooong'
142
+ assert !d.valid?
143
+ assert_equal 'LOOONG', d.errors.on(:vmax).first
144
+
145
+ d.vmax = nil
146
+ assert !d.valid?
147
+ assert_equal 'No value provided', d.errors.on(:vmax).first
148
+
149
+ d.vlen = '12'
150
+ assert !d.valid?
151
+ assert_equal 'argh', d.errors.on(:vlen).first
152
+
153
+ d.vlen = '1234565'
154
+ assert !d.valid?
155
+
156
+ d.vran = '1'
157
+ assert !d.valid?
158
+ assert_equal 'Too short, must be more than 2 characters long', d.errors.on(:vran).first
159
+
160
+ d.vran = '11111111'
161
+ assert !d.valid?
162
+ assert_equal 'argh', d.errors.on(:vran).first
163
+ end
164
+
165
+ def test_validate_inclusion
166
+ d = Dummy4.new
167
+
168
+ d.sex = 'Alien'
169
+ d.age = 1
170
+
171
+ assert !d.valid?
172
+ assert_equal 2, d.errors.count
173
+
174
+ d.sex = 'Male'
175
+ assert !d.valid?
176
+ assert_equal 1, d.errors.count
177
+
178
+ d.age = 110
179
+ assert !d.valid?
180
+ assert_equal 1, d.errors.count
181
+
182
+ d.age = 90
183
+ assert d.valid?
184
+ end
185
+
186
+ end