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,164 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # == extensions/object.rb
5
+ #
6
+ # Adds methods to the builtin Object class.
7
+ #
8
+
9
+ require 'extensions/_base'
10
+
11
+
12
+ #
13
+ # Object#singleton_class
14
+ #
15
+ ExtensionsProject.implement(Object, :singleton_class) do
16
+ class Object
17
+ #
18
+ # Returns the singleton class associated with this object. How useful this
19
+ # is I don't know, but it's an idiom that has appeared on ruby-talk several
20
+ # times.
21
+ #
22
+ def singleton_class
23
+ class << self
24
+ self
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+
31
+ #
32
+ # * Object.in?
33
+ # This has special treatment: it's included here and in enumerable.rb, so we don't
34
+ # want a warning if it's already defined.
35
+ #
36
+ unless Object.method_defined?(:in?)
37
+ ExtensionsProject.implement(Object, :in?) do
38
+ class Object
39
+ #
40
+ # Test this object for inclusion in a given collection.
41
+ #
42
+ # 45.in? (1...100) => true
43
+ #
44
+ # This method is contained in <tt>object.rb</tt> and
45
+ # <tt>enumerable.rb</tt>, because it logically belongs in both.
46
+ #
47
+ def in?(enumerable)
48
+ enumerable.include?(self)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ #
56
+ # * Object.not_nil?
57
+ #
58
+ ExtensionsProject.implement(Object, :not_nil?) do
59
+ class Object
60
+ #
61
+ # The opposite of <tt>#nil?</tt>.
62
+ #
63
+ # "hello".not_nil? # -> true
64
+ # nil.not_nil? # -> false
65
+ #
66
+ def not_nil?
67
+ not self.nil?
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ #
74
+ # * Object.non_nil?
75
+ #
76
+ ExtensionsProject.implement(Object, :non_nil?) do
77
+ class Object
78
+ #
79
+ # The opposite of <tt>#nil?</tt>.
80
+ #
81
+ # "hello".non_nil? # -> true
82
+ # nil.non_nil? # -> false
83
+ #
84
+ def non_nil?
85
+ not self.nil?
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ #
92
+ # Object#pp_s
93
+ #
94
+ ExtensionsProject.implement(Object, :pp_s) do
95
+ require 'pp'
96
+ require 'stringio'
97
+ class Object
98
+ #
99
+ # Returns a pretty-printed string of the object. Requires libraries +pp+ and
100
+ # +stringio+ from the Ruby standard library.
101
+ #
102
+ # The following code pretty-prints an object (much like +p+ plain-prints an
103
+ # object):
104
+ #
105
+ # pp object
106
+ #
107
+ # The following code captures the pretty-printing in +str+ instead of
108
+ # sending it to +STDOUT+.
109
+ #
110
+ # str = object.pp_s
111
+ #
112
+ def pp_s
113
+ pps = StringIO.new
114
+ PP.pp(self, pps)
115
+ pps.string
116
+ end
117
+ end
118
+ end
119
+
120
+ #
121
+ # Object#pp_s
122
+ #
123
+ ExtensionsProject.implement(Object, :define_method) do
124
+ class Object
125
+ #
126
+ # Defines a singleton method on the object. For example, the following are
127
+ # equivalent (assume <tt>o = Object.new</tt>):
128
+ #
129
+ # def o.add(x, y)
130
+ # x + y
131
+ # end
132
+ #
133
+ # o.define_method(:add) do |x, y|
134
+ # x + y
135
+ # end
136
+ #
137
+ # The difference is that with <tt>define_method</tt>, you can use variables
138
+ # local to the _current_ scope.
139
+ #
140
+ # x = 5
141
+ # o.define_method(:add_x) do |n|
142
+ # x + n
143
+ # end
144
+ # o.add_x(11) # -> 16
145
+ #
146
+ # You can't define such a method as <tt>add_x</tt> above with <tt>def
147
+ # o.add_x; x + n; end</tt>, as +def+ introduces a new scope.
148
+ #
149
+ # There are three ways to provide the body of the method: with a block (as
150
+ # in both examples above), or with a +Proc+ or +Method+ object. See the
151
+ # built-in method <tt>Module#define_method</tt> for details.
152
+ #
153
+ # (This method is exactly equivalent to calling <tt>Module#define_method</tt>
154
+ # in the scope of the singleton class of the object.)
155
+ #
156
+ def define_method(*args, &block)
157
+ singleton_class = class << self; self; end
158
+ singleton_class.module_eval do
159
+ define_method(*args, &block)
160
+ end
161
+ end
162
+ end
163
+ end
164
+
@@ -0,0 +1,41 @@
1
+ #!/usr/local/bin/ruby -w
2
+ #
3
+ # == extensions/ostruct.rb
4
+ #
5
+ # Adds methods to the standard library's OpenStruct class.
6
+ #
7
+
8
+ require "extensions/_base"
9
+ require 'ostruct'
10
+
11
+ #
12
+ # * OpenStruct#initialize
13
+ #
14
+ ExtensionsProject.implement(OpenStruct, :initialize) do
15
+ class OpenStruct
16
+ alias old_initialize initialize
17
+ private :old_initialize
18
+
19
+ #
20
+ # Allows the initialization of an OpenStruct with a block:
21
+ #
22
+ # person = OpenStruct.new do |p|
23
+ # p.name = 'John Smith'
24
+ # p.gender = :M
25
+ # p.age = 71
26
+ # end
27
+ #
28
+ # You can still provide a hash for initialization purposes, and even combine
29
+ # the two approaches if you wish.
30
+ #
31
+ # person = OpenStruct.new(:name => 'John Smith', :age => 31) do |p|
32
+ # p.gender = :M
33
+ # end
34
+ #
35
+ def initialize(*args) # :yield: self
36
+ old_initialize(*args)
37
+ yield self if block_given?
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,316 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # == extensions/string.rb
5
+ #
6
+ # Adds methods to the builtin String class.
7
+ #
8
+
9
+ require "extensions/_base"
10
+
11
+
12
+ ExtensionsProject.implement(String, :leftmost_indent) do
13
+ class String
14
+ #
15
+ # Returns the size of the smallest indent of any line in the string.
16
+ # Emits a warning if tabs are found, and if <tt>$VERBOSE</tt> is on.
17
+ # You can use #expand_tabs to avoid this. This method is primarily intended
18
+ # for use by #tabto and is not likely to be all that useful in its own
19
+ # right.
20
+ #
21
+ def leftmost_indent
22
+ tabs_found = false
23
+ scan(/^([ \t]*)\S/).flatten.map { |ws|
24
+ tabs_found = true if ws =~ /\t/
25
+ ws.size
26
+ }.compact.min
27
+ ensure
28
+ if tabs_found and $VERBOSE
29
+ $stderr.puts %{
30
+ String#leftmost_indent: warning: tabs treated as spaces
31
+ (value: #{self.inspect[0..30]}...")
32
+ }.strip
33
+ end
34
+ end
35
+ protected :leftmost_indent
36
+ end
37
+ end
38
+
39
+
40
+ ExtensionsProject.implement(String, :expand_tabs) do
41
+ class String
42
+ #
43
+ # Expands tabs to +n+ spaces. Non-destructive. If +n+ is 0, then tabs are
44
+ # simply removed. Raises an exception if +n+ is negative.
45
+ #
46
+ #--
47
+ # Thanks to GGaramuno for a more efficient algorithm. Very nice.
48
+ def expand_tabs(n=8)
49
+ n = n.to_int
50
+ raise ArgumentError, "n must be >= 0" if n < 0
51
+ return gsub(/\t/, "") if n == 0
52
+ return gsub(/\t/, " ") if n == 1
53
+ str = self.dup
54
+ while
55
+ str.gsub!(/^([^\t\n]*)(\t+)/) { |f|
56
+ val = ( n * $2.size - ($1.size % n) )
57
+ $1 << (' ' * val)
58
+ }
59
+ end
60
+ str
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ ExtensionsProject.implement(String, :indent) do
67
+ class String
68
+ #
69
+ # Indents the string +n+ spaces.
70
+ #
71
+ def indent(n)
72
+ n = n.to_int
73
+ return outdent(-n) if n < 0
74
+ gsub(/^/, " "*n)
75
+ end
76
+ end
77
+ end
78
+
79
+
80
+ ExtensionsProject.implement(String, :outdent) do
81
+ class String
82
+ #
83
+ # Outdents the string +n+ spaces. Initial tabs will cause problems and
84
+ # cause a warning to be emitted (if warnings are on). Relative indendation
85
+ # is always preserved. Once the block hits the beginning of the line,
86
+ # that's it. In the following example, <tt>.</tt> represents space from the
87
+ # beginning of the line.
88
+ #
89
+ # str = %{
90
+ # ..One
91
+ # ....Two
92
+ # }.outdent(4)
93
+ #
94
+ # is
95
+ #
96
+ # One
97
+ # ..Two
98
+ #
99
+ def outdent(n)
100
+ n = n.to_int
101
+ return indent(-n) if n < 0
102
+ tabto(leftmost_indent - n)
103
+ end
104
+ end
105
+ end
106
+
107
+
108
+ ExtensionsProject.implement(String, :tabto) do
109
+ class String
110
+ #
111
+ # Move the string to the <tt>n</tt>th column. Relative indentation is preserved.
112
+ # Column indices begin at 0, so the result is that the leftmost character of
113
+ # the string has +n+ spaces before it.
114
+ #
115
+ # Examples:
116
+ # "xyz".tabto(0) # -> "xyz"
117
+ # "xyz".tabto(1) # -> " xyz"
118
+ # "xyz".tabto(2) # -> " xyz"
119
+ # " xyz".tabto(1) # -> " xyz"
120
+ #
121
+ # str = <<EOF
122
+ # Hello, my name
123
+ # is Gerald.
124
+ # EOF
125
+ # str.tabto(5) == <<EOF # -> true
126
+ # Hello, my name
127
+ # is Gerald.
128
+ # EOF
129
+ #
130
+ def tabto(n)
131
+ n = n.to_int
132
+ n = 0 if n < 0
133
+ find = " " * leftmost_indent()
134
+ replace = " " * (n)
135
+ gsub(/^#{find}/, replace)
136
+ end
137
+ end
138
+ end
139
+
140
+
141
+ ExtensionsProject.implement(String, :taballto) do
142
+ class String
143
+ #
144
+ # Tabs all lines in the string to column +n+. That is, relative indentation
145
+ # is _not_ preserved.
146
+ #
147
+ def taballto(n)
148
+ n = n.to_int
149
+ n = 0 if n < 0
150
+ gsub(/^[ \t]*/, " "*n)
151
+ end
152
+ end
153
+ end
154
+
155
+
156
+ ExtensionsProject.implement(String, :trim) do
157
+ class String
158
+ #
159
+ # Trims a string:
160
+ # - removes one initial blank line
161
+ # - removes trailing spaces on each line
162
+ # - if +margin+ is given, removes initial spaces up to and including
163
+ # the margin on each line, plus one space
164
+ #
165
+ # This is designed specifically for working with inline documents.
166
+ # Here-documents are great, except they tend to go against the indentation
167
+ # of your code. This method allows a convenient way of using %{}-style
168
+ # documents. For instance:
169
+ #
170
+ # USAGE = %{
171
+ # | usage: prog [-o dir] -h file...
172
+ # | where
173
+ # | -o dir outputs to DIR
174
+ # | -h prints this message
175
+ # }.trim("|")
176
+ #
177
+ # # USAGE == "usage: prog [-o dir] -h file...\n where"...
178
+ # # (note single space to right of margin is deleted)
179
+ #
180
+ # Note carefully that if no margin string is given, then there is no
181
+ # clipping at the beginning of each line and your string will remain
182
+ # indented. You can use <tt>tabto(0)</tt> to align it with the left of
183
+ # screen (while preserving relative indentation).
184
+ #
185
+ # USAGE = %{
186
+ # usage: prog [-o dir] -h file...
187
+ # where
188
+ # -o dir outputs to DIR
189
+ # -h prints this message
190
+ # }.trim.tabto(0)
191
+ #
192
+ # # USAGE == (same as last example)
193
+ #
194
+ def trim(margin=nil)
195
+ s = self.dup
196
+ # Remove initial blank line.
197
+ s.sub!(/\A[ \t]*\n/, "")
198
+ # Get rid of the margin, if it's specified.
199
+ unless margin.nil?
200
+ margin_re = Regexp.escape(margin || "")
201
+ margin_re = /^[ \t]*#{margin_re} ?/
202
+ s.gsub!(margin_re, "")
203
+ end
204
+ # Remove trailing whitespace on each line
205
+ s.gsub!(/[ \t]+$/, "")
206
+ s
207
+ end
208
+ end
209
+ end
210
+
211
+
212
+ ExtensionsProject.implement(String, :starts_with?) do
213
+ class String
214
+ #
215
+ # Returns true iff this string starts with +str+.
216
+ # "Hello, world".starts_with?("He") # -> true
217
+ # "Hello, world".starts_with?("Green") # -> false
218
+ #
219
+ def starts_with?(str)
220
+ str = str.to_str
221
+ head = self[0, str.length]
222
+ head == str
223
+ end
224
+ end
225
+ end
226
+
227
+
228
+ ExtensionsProject.implement(String, :ends_with?) do
229
+ class String
230
+ #
231
+ # Returns true iff this string ends with +str+.
232
+ # "Hello, world".ends_with?(", world") # -> true
233
+ # "Hello, world".ends_with?("Green") # -> false
234
+ #
235
+ def ends_with?(str)
236
+ str = str.to_str
237
+ tail = self[-str.length, str.length]
238
+ tail == str
239
+ end
240
+ end
241
+ end
242
+
243
+
244
+ ExtensionsProject.implement(String, :line) do
245
+ class String
246
+ #
247
+ # Returns a line or lines from the string. +args+ can be a single integer,
248
+ # two integers or a range, as per <tt>Array#slice</tt>. The return value is
249
+ # a single String (a single line), an array of Strings (multiple lines) or
250
+ # +nil+ (out of bounds). Note that lines themselves do not contain a
251
+ # trailing newline character; that is metadata. Indexes out of bounds are
252
+ # ignored.
253
+ #
254
+ # data = " one \n two \n three \n four \n five \n"
255
+ # data.line(1) # -> " two "
256
+ # data.line(0,1) # -> [" one "]
257
+ # data.line(3..9) # -> [" four ", " five "]
258
+ # data.line(9) # -> nil
259
+ #
260
+ def line(*args)
261
+ self.split(/\n/).slice(*args)
262
+ rescue TypeError
263
+ raise TypeError,
264
+ "String#line(*args): args must be one Integer, two Integers or a Range"
265
+ rescue ArgumentError
266
+ raise ArgumentError,
267
+ "String#line(*args): args must be one Integer, two Integers or a Range"
268
+ end
269
+ end
270
+ end
271
+
272
+
273
+ ExtensionsProject.implement(String, :cmp) do
274
+ class String
275
+ #
276
+ # Compare this string to +other+, returning the first index at which they
277
+ # differ, or +nil+ if they are equal.
278
+ #
279
+ # "practise".cmp("practice") # -> 6
280
+ # "noun".cmp("nouns") # -> 5 (and vice versa)
281
+ # "fly".cmp("fly") # -> nil
282
+ #
283
+ def cmp(other)
284
+ other = other.to_str
285
+ if self == other
286
+ return nil
287
+ else
288
+ n = [self.size, other.size].min
289
+ (0..n).each do |i|
290
+ return i unless self[i] == other[i]
291
+ end
292
+ end
293
+ end
294
+ end
295
+ end
296
+
297
+
298
+ ExtensionsProject.implement(String, :join) do
299
+ class String
300
+ #
301
+ # Join all the lines of the string together, and compress spaces. The resulting string
302
+ # will have no surrounding whitespace.
303
+ #
304
+ # text = %{
305
+ # Once upon a time,
306
+ # Little Red Riding Hood ...
307
+ #
308
+ # }
309
+ #
310
+ # text.join # -> "Once upon a time, Little Red Riding Hood ..."
311
+ #
312
+ def join
313
+ gsub(/([ \t]*\n[ \t]*)+/, ' ').strip
314
+ end
315
+ end
316
+ end