nitro 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -8,7 +8,7 @@
8
8
 
9
9
  require "uri"
10
10
 
11
- module G;
11
+ module N;
12
12
 
13
13
  # = StringUtils
14
14
  #
@@ -6,7 +6,7 @@
6
6
 
7
7
  require "time.rb"
8
8
 
9
- module G;
9
+ module N;
10
10
 
11
11
  # = Time
12
12
  #
@@ -77,7 +77,7 @@ module TimeUtils
77
77
  #
78
78
  def self.time_in_day_range(time, stime=ZERO, etime=NEVER)
79
79
  if (etime <= stime)
80
- $log.debug "Invalid end time (#{etime} < #{stime})" if $DBG
80
+ Logger.debug "Invalid end time (#{etime} < #{stime})" if $DBG
81
81
  etime = NEVER
82
82
  end
83
83
 
@@ -0,0 +1,400 @@
1
+ # George Moschovitis <gm@navel.gr>
2
+ # (c) 2005 Navel, all rights reserved.
3
+ # $Id$
4
+
5
+ module N
6
+
7
+ # = Validation
8
+ #
9
+ # Implements a meta-language for validating managed
10
+ # objects. Typically used in Validator objects but can be
11
+ # included in managed objects too.
12
+ #
13
+ # == Example
14
+ #
15
+ # class User
16
+ # prop_accessor :name, String
17
+ # prop_accessor :level, Fixnum
18
+ #
19
+ # validate_length :name, :range => 2..6
20
+ # validate_unique :name, :msg => :name_allready_exists
21
+ # validate_format :name, :format => /[a-z]*/, :msg => 'invalid format', :on => :create
22
+ # end
23
+ #
24
+ # class N::CustomUserValidator
25
+ # include N::Validation
26
+ # validate_length :name, :range => 2..6, :msg_short => :name_too_short, :msg_long => :name_too_long
27
+ # end
28
+ #
29
+ # user = @request.fill(User.new)
30
+ # user.level = 15
31
+ #
32
+ # unless user.valid?
33
+ # user.save
34
+ # else
35
+ # p user.errors[:name]
36
+ # end
37
+ #
38
+ # unless user.save
39
+ # p user.errors.on(:name)
40
+ # end
41
+ #
42
+ # unless errors = N::CustomUserValidator.errors(user)
43
+ # user.save
44
+ # else
45
+ # p errors[:name]
46
+ # end
47
+ #
48
+ #--
49
+ # TODO: all validation methods should imply validate_value
50
+ # TODO: add validate_unique
51
+ #++
52
+
53
+ module Validation
54
+
55
+ # = Errors
56
+ #
57
+ # Encapsulates a list of validation errors.
58
+
59
+ class Errors
60
+ attr_accessor :errors
61
+
62
+ cattr_accessor :no_value, 'No value provided'
63
+ cattr_accessor :no_confirmation, 'Invalid confirmation'
64
+ cattr_accessor :invalid_format, 'Invalid format'
65
+ cattr_accessor :too_short, 'Too short, must be more than %d characters long'
66
+ cattr_accessor :too_long, 'Too long, must be less than %d characters long'
67
+ cattr_accessor :invalid_length, 'Must be %d characters long'
68
+ cattr_accessor :no_inclusion, 'The value is invalid'
69
+
70
+ def initialize
71
+ @errors = {}
72
+ end
73
+
74
+ def add(attr, message)
75
+ (@errors[attr] ||= []) << message
76
+ end
77
+
78
+ def on(attr)
79
+ @errors[attr]
80
+ end
81
+ alias_method :[], :on
82
+
83
+ # Yields each attribute and associated message.
84
+
85
+ def each
86
+ @errors.each_key do |attr|
87
+ @errors[attr].each { |msg| yield attr, msg }
88
+ end
89
+ end
90
+
91
+ def size
92
+ @errors.size
93
+ end
94
+ alias_method :count, :size
95
+
96
+ def empty?
97
+ @errors.empty?
98
+ end
99
+
100
+ def clear
101
+ @errors.clear
102
+ end
103
+ end
104
+
105
+ # If the validate method returns true, this
106
+ # attributes holds the errors found.
107
+
108
+ attr_accessor :errors
109
+
110
+ # Call the #validate method for this object.
111
+ # If validation errors are found, sets the
112
+ # @errors attribute to the Errors object and
113
+ # returns true.
114
+
115
+ def valid?
116
+ begin
117
+ @errors = self.class.validate(self)
118
+ return @errors.empty?
119
+ rescue NoMethodError => e
120
+ # gmosx: hmm this is potentially dangerous.
121
+ N::Validation.eval_validate(self.class)
122
+ retry
123
+ end
124
+ end
125
+
126
+ # Evaluate the 'validate' method for the calling
127
+ # class.
128
+ #
129
+ # WARNING: for the moment only evaluates for
130
+ # on == :save
131
+
132
+ def self.eval_validate(klass)
133
+ code = %{
134
+ def self.validate(obj, on = :save)
135
+ errors = Errors.new
136
+ }
137
+
138
+ for val, on in klass.__meta[:validations]
139
+ code << %{
140
+ #{val}
141
+ }
142
+ end
143
+
144
+ code << %{
145
+ return errors
146
+ end
147
+ }
148
+
149
+ # puts '-->', code, '<--'
150
+
151
+ klass.module_eval(code)
152
+ end
153
+
154
+ def self.append_features(base)
155
+ super
156
+
157
+ base.module_eval <<-"end_eval", __FILE__, __LINE__
158
+ meta :validations, []
159
+ end_eval
160
+
161
+ base.extend(MetaLanguage)
162
+ end
163
+
164
+ # = MetaLanguage
165
+ #
166
+ # Implements the Validation meta-language.
167
+
168
+ module MetaLanguage
169
+
170
+ # the postfix attached to confirmation attributes.
171
+
172
+ mattr_accessor :confirmation_postfix, '_confirmation'
173
+
174
+ # Validates that the attributes have a values, ie they are
175
+ # neither nil or empty.
176
+ #
177
+ # == Example
178
+ #
179
+ # validate_value :, :msg => 'No confirmation'
180
+
181
+ def validate_value(*params)
182
+ c = {
183
+ :msg => N::Validation::Errors.no_value,
184
+ :on => :save
185
+ }
186
+ c.update(params.pop) if params.last.is_a?(Hash)
187
+
188
+ idx = 0
189
+ for name in params
190
+ code = %{
191
+ if obj.#{name}.nil?
192
+ errors.add(:#{name}, '#{c[:msg]}')
193
+ elsif obj.#{name}.respond_to?(:empty?)
194
+ errors.add(:#{name}, '#{c[:msg]}') if obj.#{name}.empty?
195
+ end
196
+ }
197
+
198
+ __meta[:validations] << [code, c[:on]]
199
+ end
200
+ end
201
+
202
+ # Validates the confirmation of +String+ attributes.
203
+ #
204
+ # == Example
205
+ #
206
+ # validate_confirmation :password, :msg => 'No confirmation'
207
+
208
+ def validate_confirmation(*params)
209
+ c = {
210
+ :msg => N::Validation::Errors.no_confirmation,
211
+ :postfix => N::Validation::MetaLanguage.confirmation_postfix,
212
+ :on => :save
213
+ }
214
+ c.update(params.pop) if params.last.is_a?(Hash)
215
+
216
+
217
+ for name in params
218
+ confirm_name = "#{name}#{c[:postfix]}"
219
+ attr_accessor :"#{confirm_name}"
220
+
221
+ code = %{
222
+ if obj.#{confirm_name}.nil? or (obj.#{confirm_name} != obj.#{name})
223
+ errors.add(:#{name}, '#{c[:msg]}')
224
+ end
225
+ }
226
+
227
+ __meta[:validations] << [code, c[:on]]
228
+ end
229
+ end
230
+
231
+ # Validates the format of +String+ attributes.
232
+ #
233
+ # == Example
234
+ #
235
+ # validate_format :name, :format => /$A*/, :msg => 'My error', :on => :create
236
+
237
+ def validate_format(*params)
238
+ c = {
239
+ :format => nil,
240
+ :msg_no_value => N::Validation::Errors.no_value,
241
+ :msg => N::Validation::Errors.invalid_format,
242
+ :on => :save
243
+ }
244
+ c.update(params.pop) if params.last.is_a?(Hash)
245
+
246
+ unless c[:format].is_a?(Regexp)
247
+ raise(ArgumentError,
248
+ 'A regular expression must be supplied as the :format option')
249
+ end
250
+
251
+ for name in params
252
+ code = %{
253
+ if obj.#{name}.nil?
254
+ errors.add(:#{name}, '#{c[:msg_no_value]}')
255
+ else
256
+ unless obj.#{name}.to_s.match(/#{Regexp.quote(c[:format].source)}/)
257
+ errors.add(:#{name}, '#{c[:msg]}')
258
+ end
259
+ end;
260
+ }
261
+
262
+ __meta[:validations] << [code, c[:on]]
263
+ end
264
+ end
265
+
266
+ # Validates the length of +String+ attributes.
267
+ #
268
+ # == Example
269
+ #
270
+ # validate_length :name, :max => 30, :msg => 'Too long'
271
+ # validate_length :name, :min => 2, :msg => 'Too sort'
272
+ # validate_length :name, :range => 2..30
273
+ # validate_length :name, :length => 15, :msg => 'Name should be %d chars long'
274
+
275
+ def validate_length(*params)
276
+ c = {
277
+ :min => nil, :max => nil, :range => nil, :length => nil,
278
+ :msg => nil,
279
+ :msg_no_value => N::Validation::Errors.no_value,
280
+ :msg_short => N::Validation::Errors.too_short,
281
+ :msg_long => N::Validation::Errors.too_long,
282
+ :on => :save
283
+ }
284
+ c.update(params.pop) if params.last.is_a?(Hash)
285
+
286
+ min, max = c[:min], c[:max]
287
+ range, length = c[:range], c[:length]
288
+
289
+ count = 0
290
+ [min, max, range, length].each { |o| count += 1 if o }
291
+
292
+ if count == 0
293
+ raise(ArgumentError,
294
+ 'One of :min, :max, :range, :length must be provided!')
295
+ end
296
+
297
+ if count > 1
298
+ raise(ArgumentError,
299
+ 'The :min, :max, :range, :length options are mutually exclusive!')
300
+ end
301
+
302
+ for name in params
303
+ if min
304
+ c[:msg] ||= N::Validation::Errors.too_short
305
+ code = %{
306
+ if obj.#{name}.nil?
307
+ errors.add(:#{name}, '#{c[:msg_no_value]}')
308
+ elsif obj.#{name}.to_s.length < #{min}
309
+ msg = '#{c[:msg]}'
310
+ msg = (msg % #{min}) rescue msg
311
+ errors.add(:#{name}, msg)
312
+ end;
313
+ }
314
+ elsif max
315
+ c[:msg] ||= N::Validation::Errors.too_long
316
+ code = %{
317
+ if obj.#{name}.nil?
318
+ errors.add(:#{name}, '#{c[:msg_no_value]}')
319
+ elsif obj.#{name}.to_s.length > #{max}
320
+ msg = '#{c[:msg]}'
321
+ msg = (msg % #{max}) rescue msg
322
+ errors.add(:#{name}, msg)
323
+ end;
324
+ }
325
+ elsif range
326
+ code = %{
327
+ if obj.#{name}.nil?
328
+ errors.add(:#{name}, '#{c[:msg_no_value]}')
329
+ elsif obj.#{name}.to_s.length < #{range.first}
330
+ msg = '#{c[:msg_short]}'
331
+ msg = (msg % #{range.first}) rescue msg
332
+ errors.add(:#{name}, msg)
333
+ elsif obj.#{name}.to_s.length > #{range.last}
334
+ msg = '#{c[:msg_long]}'
335
+ msg = (msg % #{range.last}) rescue msg
336
+ errors.add(:#{name}, msg)
337
+ end;
338
+ }
339
+ elsif length
340
+ c[:msg] ||= N::Validation::Errors.invalid_length
341
+ code = %{
342
+ if obj.#{name}.nil?
343
+ errors.add(:#{name}, '#{c[:msg_no_value]}')
344
+ elsif obj.#{name}.to_s.length != #{length}
345
+ msg = '#{c[:msg]}'
346
+ msg = (msg % #{length}) rescue msg
347
+ errors.add(:#{name}, msg)
348
+ end;
349
+ }
350
+ end
351
+
352
+ __meta[:validations] << [code, c[:on]]
353
+ end
354
+ end
355
+
356
+ # Validates that the attributes are included in
357
+ # an enumeration.
358
+ #
359
+ # == Example
360
+ #
361
+ # validate_inclusion :sex, :in => %w{ Male Female }, :msg => 'huh??'
362
+ # validate_inclusion :age, :in => 5..99
363
+
364
+ def validate_inclusion(*params)
365
+ c = {
366
+ :in => nil,
367
+ :msg => N::Validation::Errors.no_inclusion,
368
+ :allow_nil => false,
369
+ :on => :save
370
+ }
371
+ c.update(params.pop) if params.last.is_a?(Hash)
372
+
373
+ unless c[:in].respond_to?('include?')
374
+ raise(ArgumentError,
375
+ 'An object that responds to #include? must be supplied as the :in option')
376
+ end
377
+
378
+ for name in params
379
+ if c[:allow_nil]
380
+ code = %{
381
+ unless obj.#{name}.nil? or (#{c[:in].inspect}).include?(obj.#{name})
382
+ errors.add(:#{name}, '#{c[:msg]}')
383
+ end;
384
+ }
385
+ else
386
+ code = %{
387
+ unless (#{c[:in].inspect}).include?(obj.#{name})
388
+ errors.add(:#{name}, '#{c[:msg]}')
389
+ end;
390
+ }
391
+ end
392
+
393
+ __meta[:validations] << [code, c[:on]]
394
+ end
395
+ end
396
+
397
+ end
398
+ end
399
+
400
+ end
@@ -136,13 +136,13 @@ class Application
136
136
  begin
137
137
  File.delete(@pidfile)
138
138
  Process.kill("SIGKILL", dpid)
139
- $log.info "Successfully killed #{@name} instance, pid=#{dpid}"
139
+ Logger.info "Successfully killed #{@name} instance, pid=#{dpid}"
140
140
  rescue => ex
141
- $log.error "Cannot kill #{@name} instance, pid=#{dpid}"
142
- $log.error ex
141
+ Logger.error "Cannot kill #{@name} instance, pid=#{dpid}"
142
+ Logger.error ex
143
143
  end
144
144
  else
145
- $log.error "Cannot locate pid of running instance!"
145
+ Logger.error "Cannot locate pid of running instance!"
146
146
  end
147
147
 
148
148
  # to allow for chaining
@@ -173,7 +173,7 @@ class Application
173
173
  File.open(@pidfile, 'w') {|f| f << "#{pid}\n" }
174
174
  exit!
175
175
  else # child
176
- $log.info "Daemon for '#{@name}', process id: #{Process.pid}"
176
+ Logger.info "Daemon for '#{@name}', process id: #{Process.pid}"
177
177
  end
178
178
 
179
179
  # change process group and lose control tty
@@ -207,7 +207,7 @@ class Application
207
207
  begin
208
208
  return File.open(@pidfile).read.chomp.to_i
209
209
  rescue
210
- $log.info "Could not read pid from #{@pidfile}"
210
+ Logger.info "Could not read pid from #{@pidfile}"
211
211
  return nil
212
212
  end
213
213
  end