facets 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -28,6 +28,42 @@ class Array
28
28
  # p a #=> [1,2,3]
29
29
  #
30
30
  alias_method :last!, :pop
31
+
32
+ # Iteration object.
33
+
34
+ class It
35
+ attr_reader :index, :value, :prior, :after
36
+ def initialize(array)
37
+ @array = array
38
+ @index = 0
39
+ @value = array[0]
40
+ @prior = []
41
+ @after = array[1..-1]
42
+ end
43
+ def first? ; @index == 0 ; end
44
+ def last? ; @index == @array.length ; end
45
+ private
46
+ def next_iteration
47
+ @index += 1
48
+ @prior << @value
49
+ @value = @after.shift
50
+ end
51
+ end
52
+
53
+ # Iterate over each element of array using an iteration object.
54
+
55
+ def each_iteration
56
+ if block_given?
57
+ it = It.new(self)
58
+ each do |e|
59
+ yield(it)
60
+ it.send(:next_iteration)
61
+ end
62
+ else
63
+ return Enumerable::Enumerator.new(self, :each_iteration)
64
+ end
65
+ end
66
+
31
67
  end
32
68
 
33
69
 
@@ -5,6 +5,7 @@ require 'facets/kernel/val.rb'
5
5
  require 'facets/kernel/metaid.rb'
6
6
  require 'facets/kernel/instance.rb'
7
7
  require 'facets/kernel/tap.rb'
8
+ require 'facets/kernel/ergo.rb'
8
9
  require 'facets/kernel/object.rb'
9
10
  require 'facets/kernel/withattr.rb'
10
11
  require 'facets/kernel/deepcopy.rb'
@@ -17,3 +18,4 @@ require 'facets/kernel/ask.rb'
17
18
  require 'facets/kernel/respond.rb'
18
19
  require 'facets/kernel/silence.rb'
19
20
  require 'facets/kernel/report.rb'
21
+
@@ -0,0 +1,40 @@
1
+ require 'facets/functor'
2
+
3
+ module Kernel
4
+
5
+ # Yield self -or- return self.
6
+ #
7
+ # "a".ergo.upcase #=> "A"
8
+ # nil.ergo.foobar #=> nil
9
+ #
10
+ # "a".ergo{ |o| o.upcase } #=> "A"
11
+ # nil.ergo{ |o| o.foobar } #=> nil
12
+ #
13
+ # This is like #tap, but tap yields self -and- returns self.
14
+ #
15
+ # CREDIT Daniel DeLorme
16
+
17
+ def ergo &b
18
+ if block_given?
19
+ b.arity == 1 ? yield(self) : instance_eval(&b)
20
+ else
21
+ self
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ class NilClass
28
+
29
+ # Compliments Kernel#ergo.
30
+ #
31
+ # "a".ergo{ |o| o.upcase } #=> "A"
32
+ # nil.ergo{ |o| o.bar } #=> nil
33
+ #
34
+ # CREDIT Daniel DeLorme
35
+
36
+ def ergo
37
+ @_ergo ||= Functor.new{ nil }
38
+ @_ergo unless block_given?
39
+ end
40
+ end
@@ -15,13 +15,11 @@
15
15
  #
16
16
  module Kernel
17
17
 
18
- # Yield self and return self.
18
+ # Yield self -and- return self.
19
19
 
20
- def tap &b
21
- if b.arity == 1
22
- yield self
23
- else
24
- instance_eval(&b)
20
+ def tap(&b)
21
+ if block_given?
22
+ b.arity == 1 ? yield(self) : instance_eval(&b)
25
23
  end
26
24
  self
27
25
  end
@@ -1,2 +1 @@
1
1
  require 'facets/nilclass/status.rb'
2
- require 'facets/nilclass/ergo.rb'
@@ -18,37 +18,45 @@
18
18
  #
19
19
  class String
20
20
 
21
- # CREDIT Phil Tomson
21
+ # Title case.
22
+
23
+ def titlecase
24
+ gsub(/\b\w/){$&.upcase}
25
+ end
22
26
 
23
27
  # Return true if the string is capitalized, otherwise false.
24
28
  #
25
29
  # "THIS".capitalized? #=> true
26
30
  # "This".capitalized? #=> true
27
31
  # "this".capitalized? #=> false
32
+ #
33
+ # CREDIT: Phil Tomson
28
34
 
29
35
  def capitalized?
30
36
  self =~ /^[A-Z]/
31
37
  end
32
38
 
33
- # CREDIT Phil Tomson
34
39
 
35
40
  # Return true if the string is lowercase (downcase), otherwise false.
36
41
  #
37
42
  # "THIS".downcase? #=> false
38
43
  # "This".downcase? #=> false
39
44
  # "this".downcase? #=> true
45
+ #
46
+ # CREDIT Phil Tomson
40
47
 
41
48
  def downcase?
42
49
  downcase == self
43
50
  end
44
51
 
45
- # CREDIT Phil Tomson
46
52
 
47
53
  # Is the string upcase/uppercase?
48
54
  #
49
55
  # "THIS".upcase? #=> true
50
56
  # "This".upcase? #=> false
51
57
  # "this".upcase? #=> false
58
+ #
59
+ # CREDIT Phil Tomson
52
60
 
53
61
  def upcase?
54
62
  self.upcase == self
@@ -61,45 +69,3 @@ class String
61
69
  alias_method :uppercase?, :upcase?
62
70
  end
63
71
 
64
-
65
-
66
- # _____ _
67
- # |_ _|__ ___| |_
68
- # | |/ _ \/ __| __|
69
- # | | __/\__ \ |_
70
- # |_|\___||___/\__|
71
- #
72
- =begin test
73
-
74
- require 'test/unit'
75
-
76
- #class String
77
- # include Compare
78
- #end
79
-
80
- class TestStringCase < Test::Unit::TestCase
81
-
82
- def test_capitalized?
83
- assert( 'Abc'.capitalized? )
84
- end
85
-
86
- def test_downcase?
87
- assert( 'abc'.downcase? )
88
- end
89
-
90
- def test_lowercase?
91
- assert( 'abc'.lowercase? )
92
- end
93
-
94
- def test_upcase?
95
- assert( 'ABC'.upcase? )
96
- end
97
-
98
- def test_uppercase?
99
- assert( 'ABC'.uppercase? )
100
- end
101
-
102
- end
103
-
104
- =end
105
-
@@ -0,0 +1 @@
1
+ require 'facets/array/indexable.rb'
@@ -0,0 +1 @@
1
+ require 'facets/kernel/ergo.rb'
@@ -0,0 +1 @@
1
+ require 'facets/string/case.rb'
@@ -108,6 +108,7 @@ module Console
108
108
  pre = cargs.preoptions
109
109
  cmd, argv = *cargs.subcommand
110
110
  args, opts = *argv
111
+
111
112
  if is_a?(UniversalOptions)
112
113
  new(pre, opts).call(cmd, args, opts)
113
114
  else
@@ -145,6 +146,7 @@ module Console
145
146
  #
146
147
 
147
148
  def initialize(*options)
149
+ @master_options = {}
148
150
  initialize_options(*options)
149
151
  end
150
152
 
@@ -155,12 +157,13 @@ module Console
155
157
  begin
156
158
  opt, val = nil, nil
157
159
  options.each do |opt, val|
160
+ opt = opt.gsub('-','_')
158
161
  send("#{opt}=", val)
159
162
  end
160
163
  rescue NoMethodError
161
164
  option_missing(opt, val)
162
165
  end
163
- @master_options = options
166
+ @master_options.update(options)
164
167
  end
165
168
 
166
169
  public
@@ -212,8 +215,15 @@ module Console
212
215
 
213
216
  class Command
214
217
 
218
+ def self.option_arity(arity_hash=nil)
219
+ if arity_hash
220
+ (@option_arity ||= {}).merge!(arity_hash)
221
+ end
222
+ @option_arity
223
+ end
224
+
215
225
  def self.start(line=nil)
216
- cargs = Console::Argument.new(line || ARGV)
226
+ cargs = Console::Argument.new(line || ARGV, option_arity)
217
227
  pre = cargs.preoptions
218
228
  args, opts = *cargs.parameters
219
229
  new(args, opts).call
@@ -24,37 +24,175 @@
24
24
  # AUTHORS:
25
25
  #
26
26
  # - George Moschovitis
27
+ # - TransLogathon
27
28
 
28
-
29
- require 'logger'
29
+ require "logger"
30
+ require "time"
31
+ require "facets/ansicode"
30
32
 
31
33
  # = Logger
32
34
  #
33
35
  # Extended variation of Ruby's standard Logger library.
36
+ # Mainly for compatibility purposes (with what?)
37
+ #
38
+ # log = Logger.new
39
+ #
40
+ # log.setup_format do |severity, timestamp, progname, msg|
41
+ # Logger::SIMPLE_FORMAT % [severity, msg]
42
+ # end
43
+ #
44
+ # === Convention
45
+ #
46
+ # When using debug level logger messages always append 'if $DBG'
47
+ # at the end. This hack is needed because Ruby does not support
48
+ # lazy evaluation (lisp macros).
34
49
  #
50
+ # TODO What's all this about then?
51
+
35
52
  class Logger
53
+ # Some available logging formats.
54
+ SIMPLE_FORMAT = "%5s: %s\n"
55
+ DETAILED_FORMAT = "%s %5s: %s\n"
56
+
57
+ # Why these names ?
58
+ alias_method :devel, :debug
59
+ alias_method :fine, :debug
60
+
61
+ # Prints a trace message to DEBUGLOG (at debug level).
62
+ # Useful for emitting the value of variables, etc. Use
63
+ # like this:
64
+ #
65
+ # x = y = 5
66
+ # trace 'x' # -> 'x = 5'
67
+ # trace 'x ** y' # -> 'x ** y = 3125'
68
+ #
69
+ # If you have a more complicated value, like an array of
70
+ # hashes, then you'll probably want to use an alternative
71
+ # output format. For instance:
72
+ #
73
+ # trace 'value', :yaml
74
+ #
75
+ # Valid output format values (the _style_ parameter) are:
76
+ #
77
+ # :p :inspect
78
+ # :pp (pretty-print, using 'pp' library)
79
+ # :s :to_s
80
+ # :y :yaml :to_yaml (using the 'yaml' library')
81
+ #
82
+ # The default is <tt>:p</tt>.
83
+ #
84
+ # CREDITS:
85
+ #
86
+ # This code comes straight from the dev-utils Gem.
87
+ # Author: Gavin Sinclair <gsinclair@soyabean.com.au>
88
+
89
+ def trace(expr, style=:p)
90
+ unless expr.respond_to? :to_str
91
+ warn "trace: Can't evaluate the given value: #{caller.first}"
92
+ else
93
+ raise "FACETS: binding/or_caller is no longer possible"
94
+ require "facets/core/binding/self/of_caller"
95
+
96
+ Binding.of_caller do |b|
97
+ value = b.eval(expr.to_str)
98
+ formatter = TRACE_STYLES[style] || :inspect
99
+ case formatter
100
+ when :pp then require 'pp'
101
+ when :y, :yaml, :to_yaml then require 'yaml'
102
+ end
103
+ value_s = value.send(formatter)
104
+ message = "#{expr} = #{value_s}"
105
+ lines = message.split(/\n/)
106
+ indent = " "
107
+ debug(lines.shift)
108
+ lines.each do |line|
109
+ debug(indent + line)
110
+ end
111
+ end
112
+ end
113
+ end
36
114
 
37
- private
115
+ TRACE_STYLES = {} # :nodoc:
116
+ TRACE_STYLES.update(
117
+ :pp => :pp_s, :s => :to_s, :p => :inspect,
118
+ :y => :to_yaml, :yaml => :to_yaml,
119
+ :inspect => :inspect, :to_yaml => :to_yaml
120
+ )
38
121
 
39
- # Dictate the way in which this logger should format the messages
40
- # it displays. This method requires a block. The block should return
41
- # formatted strings given severity, timestamp, msg, progname.
122
+ # Dictate the way in which this logger should format the
123
+ # messages it displays. This method requires a block. The
124
+ # block should return formatted strings given severity,
125
+ # timestamp, msg, progname.
42
126
  #
43
- # Useless example:
127
+ # === Example
44
128
  #
45
129
  # logger = Logger.new
46
- # logger.format do |severity, timestamp, msg, progname|
130
+ # logger.setup_format do |severity, timestamp, msg, progname|
47
131
  # "#{progname}@#{timestamp} - #{severity}::#{msg}"
48
132
  # end
49
- #
50
- def format(&format_proc)
51
- raise 'block expected' unless format_proc
133
+
134
+ def setup_format(&format_proc)
135
+ raise "Formating block needed" unless format_proc
52
136
  @format_proc = format_proc
53
137
  end
54
138
 
55
- # hackish use of *args, give me some love
56
- def format_message(*args)
57
- @format_proc ? @format_proc.call(*args) : super(*args)
139
+ private
140
+
141
+ attr_accessor :format_proc
142
+
143
+ alias_method :format_message_without_proc, :format_message # :nodoc:
144
+
145
+ def format_message(*args) # :nodoc:
146
+ @format_proc ? @format_proc.call(*args) : format_message_without_proc(*args)
58
147
  end
59
148
 
60
149
  end
150
+
151
+
152
+ module Console
153
+
154
+ class Logger < ::Logger
155
+
156
+ attr_accessor :style
157
+
158
+ def style
159
+ @style ||= Style.new
160
+ end
161
+
162
+ def info(str)
163
+ return if level > Logger::INFO
164
+ self << style.info(str)
165
+ super
166
+ self << Console::ANSICode.clear
167
+ end
168
+
169
+ def warn(str)
170
+ self << style.warn(str)
171
+ super
172
+ self << Console::ANSICode.clear
173
+ end
174
+
175
+ def error(str)
176
+ return if level > Logger::ERROR
177
+ self << style.error(str)
178
+ super
179
+ self << Console::ANSICode.clear
180
+ end
181
+
182
+ def debug(str)
183
+ self << style.debug(str)
184
+ super
185
+ self << Console::ANSICode.clear
186
+ end
187
+
188
+ # Logger Style
189
+
190
+ class Style
191
+ def info(str) ; ANSICode.green ; end
192
+ def warn(str) ; ANSICode.cyan ; end
193
+ def error(str) ; ANSICode.bold + ANSICode.red ; end
194
+ def debug(str) ; '' ; end
195
+ end
196
+
197
+ end
198
+ end
@@ -0,0 +1,445 @@
1
+ require 'facets/class/cattr'
2
+ require 'facets/module/on_included'
3
+ require 'facets/inheritor'
4
+ require 'facets/settings'
5
+
6
+ module Glue
7
+
8
+ # Implements a meta-language for validating managed
9
+ # objects. Typically used in Validator objects but can be
10
+ # included in managed objects too.
11
+ #
12
+ # Additional og-related validation macros can be found
13
+ # in lib/og/validation.
14
+ #
15
+ # The following validation macros are available:
16
+ #
17
+ # * validate_value
18
+ # * validate_confirmation
19
+ # * validate_format
20
+ # * validate_length
21
+ # * validate_inclusion
22
+ #
23
+ # Og/Database specific validation methods are added in the
24
+ # file og/validation.rb
25
+ #
26
+ # === Example
27
+ #
28
+ # class User
29
+ # attr_accessor :name, String
30
+ # attr_accessor :level, Fixnum
31
+ #
32
+ # validate_length :name, :range => 2..6
33
+ # validate_unique :name, :msg => :name_allready_exists
34
+ # validate_format :name, :format => /[a-z]*/, :msg => 'invalid format', :on => :create
35
+ # end
36
+ #
37
+ # class CustomUserValidator
38
+ # include Validation
39
+ # validate_length :name, :range => 2..6, :msg_short => :name_too_short, :msg_long => :name_too_long
40
+ # end
41
+ #
42
+ # user = @request.fill(User.new)
43
+ # user.level = 15
44
+ #
45
+ # unless user.valid?
46
+ # user.save
47
+ # else
48
+ # p user.errors[:name]
49
+ # end
50
+ #
51
+ # unless user.save
52
+ # p user.errors.on(:name)
53
+ # end
54
+ #
55
+ # unless errors = CustomUserValidator.errors(user)
56
+ # user.save
57
+ # else
58
+ # p errors[:name]
59
+ # end
60
+ #--
61
+ # TODO: all validation methods should imply validate_value.
62
+ #++
63
+
64
+ module Validation
65
+
66
+ # The postfix attached to confirmation attributes.
67
+
68
+ setting :confirmation_postfix, :default => '_confirmation', :doc => 'The postfix attached to confirmation attributes.'
69
+
70
+ # Encapsulates a list of validation errors.
71
+
72
+ class Errors
73
+ attr_accessor :errors
74
+
75
+ setting :no_value, :default => 'No value provided'
76
+ setting :no_confirmation, :default => 'Invalid confirmation'
77
+ setting :invalid_format, :default => 'Invalid format'
78
+ setting :too_short, :default => 'Too short, must be more than %d characters long'
79
+ setting :too_long, :default => 'Too long, must be less than %d characters long'
80
+ setting :invalid_length, :default => 'Must be %d characters long'
81
+ setting :no_inclusion, :default => 'The value is invalid'
82
+ setting :no_numeric, :default => 'The value must be numeric'
83
+ setting :not_unique, :default => 'The value is already used'
84
+
85
+ def initialize(errors = {})
86
+ @errors = errors
87
+ end
88
+
89
+ def add(attr, message)
90
+ (@errors[attr] ||= []) << message
91
+ end
92
+
93
+ def on(attr)
94
+ @errors[attr]
95
+ end
96
+ alias_method :[], :on
97
+
98
+ # Yields each attribute and associated message.
99
+
100
+ def each
101
+ @errors.each_key do |attr|
102
+ @errors[attr].each { |msg| yield attr, msg }
103
+ end
104
+ end
105
+
106
+ def size
107
+ @errors.size
108
+ end
109
+ alias_method :count, :size
110
+
111
+ def empty?
112
+ @errors.empty?
113
+ end
114
+
115
+ def clear
116
+ @errors.clear
117
+ end
118
+
119
+ def to_a
120
+ @errors.inject([]) { |a, kv| a << kv }
121
+ end
122
+
123
+ def join(glue)
124
+ @errors.to_a.join(glue)
125
+ end
126
+ end
127
+
128
+ # A Key is used to uniquely identify a validation rule.
129
+
130
+ class Key
131
+ attr_reader :validation
132
+ attr_reader :field
133
+
134
+ def initialize(validation, field)
135
+ @validation, @field = validation.to_s, field.to_s
136
+ end
137
+
138
+ def hash
139
+ "#{@validation}-#{@field}".hash
140
+ end
141
+
142
+ def ==(other)
143
+ self.validation == other.validation and self.field == other.field
144
+ end
145
+ end
146
+
147
+ # If the validate method returns true, this
148
+ # attributes holds the errors found.
149
+
150
+ attr_accessor :errors
151
+
152
+ # Call the #validate method for this object.
153
+ # If validation errors are found, sets the
154
+ # @errors attribute to the Errors object and
155
+ # returns true.
156
+
157
+ def valid?
158
+ validate
159
+ @errors.empty?
160
+ end
161
+
162
+ # Evaluate the class and see if it is valid.
163
+ # Can accept any parameter for 'on' event,
164
+ # and defaults to :save
165
+
166
+ def validate(on = :save)
167
+ @errors = Errors.new
168
+
169
+ return if self.class.validations.length == 0
170
+
171
+ for event, block in self.class.validations
172
+ block.call(self) if event == on.to_sym
173
+ end
174
+ end
175
+
176
+ on_included %{
177
+ base.module_eval do
178
+ inheritor(:validations, [], :+) unless @validations
179
+ # THINK: investigate carefuly!
180
+ def self.included(cbase)
181
+ super
182
+ cbase.send :include, Glue::Validation
183
+ end
184
+ end
185
+ base.extend(ClassMethods)
186
+ }
187
+
188
+ # Implements the Validation meta-language.
189
+
190
+ module ClassMethods
191
+ # Validates that the attributes have a values, ie they are
192
+ # neither nil or empty.
193
+ #
194
+ # === Example
195
+ #
196
+ # validate_value :param, :msg => 'No confirmation'
197
+
198
+ def validate_value(*params)
199
+ c = parse_config(params, :msg => Glue::Validation::Errors.no_value, :on => :save)
200
+
201
+ params.each do |field|
202
+ define_validation(:value, field, c[:on]) do |obj|
203
+ value = obj.send(field)
204
+ obj.errors.add(field, c[:msg]) if value.nil? || (value.respond_to?(:empty?) && value.empty?)
205
+ end
206
+ end
207
+ end
208
+ =begin
209
+ # Validates the confirmation of +String+ attributes.
210
+ #
211
+ # === Example
212
+ #
213
+ # validate_confirmation :password, :msg => 'No confirmation'
214
+
215
+ def validate_confirmation(*params)
216
+ c = parse_config(params,
217
+ :msg => Glue::Validation::Errors.no_confirmation,
218
+ :postfix => Glue::Validation.confirmation_postfix,
219
+ :on => :save
220
+ )
221
+
222
+ params.each do |field|
223
+ confirm_name = field.to_s + c[:postfix]
224
+ attr_accessor confirm_name.to_sym
225
+
226
+ define_validation(:confirmation, field, c[:on]) do |obj|
227
+ value = obj.send(field)
228
+ obj.errors.add(field, c[:msg]) if value.nil? or obj.send(confirm_name) != value
229
+ end
230
+ end
231
+ end
232
+ =end
233
+ # Validates the format of +String+ attributes.
234
+ # WARNING: regexp options are ignored.
235
+ #
236
+ # === Example
237
+ #
238
+ # validate_format :name, :format => /$A*/, :msg => 'My error', :on => :create
239
+ #--
240
+ # FIXME: how to get the Regexp options?
241
+ #++
242
+
243
+ def validate_format(*params)
244
+ c = parse_config(params,
245
+ :format => nil,
246
+ :msg_no_value => Glue::Validation::Errors.no_value,
247
+ :msg => Glue::Validation::Errors.invalid_format,
248
+ :on => :save
249
+ )
250
+
251
+ unless c[:format].is_a?(Regexp)
252
+ raise ArgumentError, "A regular expression must be supplied as the :format option for validate_format."
253
+ end
254
+
255
+ params.each do |field|
256
+ define_validation(:format, field, c[:on]) do |obj|
257
+ value = obj.send(field)
258
+ obj.errors.add(field, c[:msg]) if value.to_s !~ c[:format]
259
+ end
260
+ end
261
+ end
262
+
263
+ # Validates the length of +String+ attributes.
264
+ #
265
+ # === Example
266
+ #
267
+ # validate_length :name, :max => 30, :msg => 'Too long'
268
+ # validate_length :name, :min => 2, :msg => 'Too sort'
269
+ # validate_length :name, :range => 2..30
270
+ # validate_length :name, :length => 15, :msg => 'Name should be %d chars long'
271
+
272
+ LENGTHS = [:min, :max, :range, :length].freeze
273
+
274
+ def validate_length(*params)
275
+ c = parse_config(params,
276
+ # :lengths => {:min => nil, :max => nil, :range => nil, :length => nil},
277
+ :min => nil, :max => nil, :range => nil, :length => nil,
278
+ :msg => nil,
279
+ :msg_no_value => Glue::Validation::Errors.no_value,
280
+ :msg_short => Glue::Validation::Errors.too_short,
281
+ :msg_long => Glue::Validation::Errors.too_long,
282
+ :msg_invalid => Glue::Validation::Errors.invalid_length,
283
+ :on => :save
284
+ )
285
+
286
+ length_params = c.reject {|k,v| !LENGTHS.include?(k) || v.nil? }
287
+ valid_count = length_params.reject{|k,v| v.nil?}.length
288
+
289
+ if valid_count == 0
290
+ raise ArgumentError, 'One of :min, :max, :range, or :length must be provided!'
291
+ elsif valid_count > 1
292
+ raise ArgumentError, 'You can only use one of :min, :max, :range, or :length options!'
293
+ end
294
+
295
+ operation, required = length_params.keys[0], length_params.values[0]
296
+
297
+ params.each do |field|
298
+ define_validation(:length, field, c[:on]) do |obj|
299
+ msg = c[:msg]
300
+ value = obj.send(field)
301
+ if value.nil?
302
+ obj.errors.add(field, c[:msg_no_value])
303
+ else
304
+ case operation
305
+ when :min
306
+ msg ||= c[:msg_short]
307
+ obj.errors.add(field, msg % required) if value.length < required
308
+ when :max
309
+ msg ||= c[:msg_long]
310
+ obj.errors.add(field, msg % required) if value.length > required
311
+ when :range
312
+ min, max = required.first, required.last
313
+ if value.length < min
314
+ msg ||= c[:msg_short]
315
+ obj.errors.add(field, msg % min)
316
+ end
317
+ if value.length > max
318
+ msg ||= c[:msg_long]
319
+ obj.errors.add(field, msg % min)
320
+ end
321
+ when :length
322
+ msg ||= c[:msg_invalid]
323
+ obj.errors.add(field, msg % required) if value.length != required
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
329
+
330
+ # Validates that the attributes are included in
331
+ # an enumeration.
332
+ #
333
+ # === Example
334
+ #
335
+ # validate_inclusion :sex, :in => %w{ Male Female }, :msg => 'huh??'
336
+ # validate_inclusion :age, :in => 5..99
337
+
338
+ def validate_inclusion(*params)
339
+ c = parse_config(params,
340
+ :in => nil,
341
+ :msg => Glue::Validation::Errors.no_inclusion,
342
+ :allow_nil => false,
343
+ :on => :save
344
+ )
345
+
346
+ unless c[:in].respond_to?('include?')
347
+ raise(ArgumentError, 'An object that responds to #include? must be supplied as the :in option')
348
+ end
349
+
350
+ params.each do |field|
351
+ define_validation(:inclusion, field, c[:on]) do |obj|
352
+ value = obj.send(field)
353
+ unless (c[:allow_nil] && value.nil?) or c[:in].include?(value)
354
+ obj.errors.add(field, c[:msg])
355
+ end
356
+ end
357
+ end
358
+ end
359
+
360
+ # Validates that the attributes have numeric values.
361
+ #
362
+ # [+:integer+]
363
+ # Only accept integers
364
+ #
365
+ # [+:msg]
366
+ # Custom message
367
+ #
368
+ # [+:on:]
369
+ # When to validate
370
+ #
371
+ # === Example
372
+ #
373
+ # validate_numeric :age, :msg => 'Must be an integer'
374
+
375
+ def validate_numeric(*params)
376
+ c = parse_config(params,
377
+ :integer => false,
378
+ :msg => Glue::Validation::Errors.no_numeric,
379
+ :on => :save
380
+ )
381
+
382
+ params.each do |field|
383
+ define_validation(:numeric, field, c[:on]) do |obj|
384
+ value = obj.send(field).to_s
385
+ if c[:integer]
386
+ unless value =~ /^[\+\-]*\d+$/
387
+ obj.errors.add(field, c[:msg])
388
+ end
389
+ else
390
+ begin
391
+ Float(value)
392
+ rescue ArgumentError, TypeError
393
+ obj.errors.add(field, c[:msg])
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end
399
+ alias_method :validate_numericality, :validate_numeric
400
+
401
+ protected
402
+
403
+ # Parse the configuration for a validation by comparing
404
+ # the default options with the user-specified options,
405
+ # and returning the results.
406
+
407
+ def parse_config(params, defaults = {})
408
+ defaults.update(params.pop) if params.last.is_a?(Hash)
409
+ defaults
410
+ end
411
+
412
+ # Define a validation for this class on the specified event.
413
+ # Specify the on event for when this validation should be
414
+ # checked.
415
+ #
416
+ # An extra check is performed to avoid multiple validations.
417
+ #
418
+ # This example creates a validation for the 'save' event,
419
+ # and will add an error to the record if the 'name' property
420
+ # of the validating object is nil.
421
+ #
422
+ # === Example
423
+ #
424
+ # field = :name
425
+ #
426
+ # define_validation(:value, field, :save) do |object|
427
+ # object.errors.add(field, "You must set a value for #{field}") if object.send(field).nil?
428
+ # end
429
+
430
+ def define_validation(val, field, on = :save, &block)
431
+ vk = Validation::Key.new(val, field)
432
+ unless validations.find { |v| v[2] == vk }
433
+ validations! << [on, block, vk]
434
+ end
435
+ end
436
+
437
+ end
438
+
439
+ end
440
+
441
+ end
442
+
443
+ class Module # :nodoc: all
444
+ include Glue::Validation::ClassMethods
445
+ end
@@ -1,5 +1,10 @@
1
1
  = Facets Revision History
2
2
 
3
+ == 2.1.1 / 2007-11-16
4
+
5
+ * Fixed bug in command.rb that clobber options.
6
+ * Added kernel/ergo.rb.
7
+
3
8
  == 2.1.0 / 2007-11-10
4
9
 
5
10
  * Major Changes
@@ -107,6 +107,7 @@ lib/core/facets/kernel/callstack.rb
107
107
  lib/core/facets/kernel/constant.rb
108
108
  lib/core/facets/kernel/deepcopy.rb
109
109
  lib/core/facets/kernel/dir.rb
110
+ lib/core/facets/kernel/ergo.rb
110
111
  lib/core/facets/kernel/instance.rb
111
112
  lib/core/facets/kernel/metaid.rb
112
113
  lib/core/facets/kernel/object.rb
@@ -139,7 +140,6 @@ lib/core/facets/module/require.rb
139
140
  lib/core/facets/module/traits.rb
140
141
  lib/core/facets/module.rb
141
142
  lib/core/facets/nilclass
142
- lib/core/facets/nilclass/ergo.rb
143
143
  lib/core/facets/nilclass/status.rb
144
144
  lib/core/facets/nilclass.rb
145
145
  lib/core/facets/numeric
@@ -202,6 +202,7 @@ lib/methods/facets/array/contains.rb
202
202
  lib/methods/facets/array/delete_unless.rb
203
203
  lib/methods/facets/array/delete_values.rb
204
204
  lib/methods/facets/array/delete_values_at.rb
205
+ lib/methods/facets/array/each_iteration.rb
205
206
  lib/methods/facets/array/first.rb
206
207
  lib/methods/facets/array/join_sentence.rb
207
208
  lib/methods/facets/array/last.rb
@@ -521,6 +522,7 @@ lib/methods/facets/module/revisal.rb
521
522
  lib/methods/facets/module/wrap.rb
522
523
  lib/methods/facets/module/wrap_method.rb
523
524
  lib/methods/facets/nilclass
525
+ lib/methods/facets/nilclass/ergo.rb
524
526
  lib/methods/facets/nilclass/to_bool.rb
525
527
  lib/methods/facets/nilclass/to_f.rb
526
528
  lib/methods/facets/nilclass/to_h.rb
@@ -601,6 +603,7 @@ lib/methods/facets/string/succ.rb
601
603
  lib/methods/facets/string/tab.rb
602
604
  lib/methods/facets/string/taballto.rb
603
605
  lib/methods/facets/string/tabto.rb
606
+ lib/methods/facets/string/titlecase.rb
604
607
  lib/methods/facets/string/to_b.rb
605
608
  lib/methods/facets/string/to_const.rb
606
609
  lib/methods/facets/string/to_date.rb
@@ -729,11 +732,11 @@ lib/more/facets/syncarray.rb
729
732
  lib/more/facets/synchash.rb
730
733
  lib/more/facets/timer.rb
731
734
  lib/more/facets/times.rb
732
- lib/more/facets/tracepoint.rb
733
735
  lib/more/facets/tuple.rb
734
736
  lib/more/facets/typecast.rb
735
737
  lib/more/facets/uninheritable.rb
736
738
  lib/more/facets/uploadutils.rb
739
+ lib/more/facets/validation.rb
737
740
  lib/more/facets/version.rb
738
741
  lib/more/facets/yaml.rb
739
742
  lib/more/facets/ziputils.rb
@@ -743,7 +746,7 @@ log/history.txt
743
746
  log/release.txt
744
747
  log/todo.txt
745
748
  meta
746
- meta/facets-2.1.0.roll
749
+ meta/facets-2.1.1.roll
747
750
  meta/google_ad.html
748
751
  meta/icli.yaml
749
752
  meta/manifest.txt
@@ -768,6 +771,8 @@ task/release
768
771
  task/special
769
772
  task/special/quickopts
770
773
  task/stats
774
+ task/svn
775
+ task/svn/tag
771
776
  task/syntax
772
777
  task/test
773
778
  task/testeach
@@ -16,6 +16,8 @@ require 'facets/module/require'
16
16
 
17
17
  config = configuration['methods']
18
18
 
19
+ p config
20
+
19
21
  source = config['source'] # from where
20
22
  output = config['output'] # to where
21
23
  ignore = config['ignore'] # classes/modules to ignore
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ratch
2
+
3
+ # Tag the current version.
4
+
5
+ main :svn_tag do
6
+
7
+ roll = glob('meta/*.roll')[0]
8
+ pkgn = File.basename(roll).chomp('.roll')
9
+ indx = pkgn.rindex('-')
10
+ name = pkgn[0...indx]
11
+ vers = pkgn[indx+1..-1]
12
+
13
+ developername = ENV['RUBYFORGE_USERNAME']
14
+
15
+ from = "svn+ssh://#{developername}@rubyforge.org/var/svn/facets/trunk"
16
+ twrd = "svn+ssh://#{developername}@rubyforge.org/var/svn/facets/tags/#{vers}"
17
+ mesg = "TAG #{vers}"
18
+
19
+ svn "copy #{from} #{twrd} -m '#{mesg}'"
20
+
21
+ end
22
+
metadata CHANGED
@@ -3,9 +3,9 @@ rubygems_version: 0.9.4.6
3
3
  specification_version: 2
4
4
  name: facets
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.1.0
7
- date: 2007-11-10 00:00:00 -05:00
8
- summary: Premium Core Extensions and Standard Additions
6
+ version: 2.1.1
7
+ date: 2007-11-16 00:00:00 -05:00
8
+ summary: ""
9
9
  require_paths:
10
10
  - lib/methods
11
11
  - lib/more
@@ -147,6 +147,7 @@ files:
147
147
  - lib/core/facets/kernel/constant.rb
148
148
  - lib/core/facets/kernel/deepcopy.rb
149
149
  - lib/core/facets/kernel/dir.rb
150
+ - lib/core/facets/kernel/ergo.rb
150
151
  - lib/core/facets/kernel/instance.rb
151
152
  - lib/core/facets/kernel/metaid.rb
152
153
  - lib/core/facets/kernel/object.rb
@@ -179,7 +180,6 @@ files:
179
180
  - lib/core/facets/module/traits.rb
180
181
  - lib/core/facets/module.rb
181
182
  - lib/core/facets/nilclass
182
- - lib/core/facets/nilclass/ergo.rb
183
183
  - lib/core/facets/nilclass/status.rb
184
184
  - lib/core/facets/nilclass.rb
185
185
  - lib/core/facets/numeric
@@ -242,6 +242,7 @@ files:
242
242
  - lib/methods/facets/array/delete_unless.rb
243
243
  - lib/methods/facets/array/delete_values.rb
244
244
  - lib/methods/facets/array/delete_values_at.rb
245
+ - lib/methods/facets/array/each_iteration.rb
245
246
  - lib/methods/facets/array/first.rb
246
247
  - lib/methods/facets/array/join_sentence.rb
247
248
  - lib/methods/facets/array/last.rb
@@ -561,6 +562,7 @@ files:
561
562
  - lib/methods/facets/module/wrap.rb
562
563
  - lib/methods/facets/module/wrap_method.rb
563
564
  - lib/methods/facets/nilclass
565
+ - lib/methods/facets/nilclass/ergo.rb
564
566
  - lib/methods/facets/nilclass/to_bool.rb
565
567
  - lib/methods/facets/nilclass/to_f.rb
566
568
  - lib/methods/facets/nilclass/to_h.rb
@@ -641,6 +643,7 @@ files:
641
643
  - lib/methods/facets/string/tab.rb
642
644
  - lib/methods/facets/string/taballto.rb
643
645
  - lib/methods/facets/string/tabto.rb
646
+ - lib/methods/facets/string/titlecase.rb
644
647
  - lib/methods/facets/string/to_b.rb
645
648
  - lib/methods/facets/string/to_const.rb
646
649
  - lib/methods/facets/string/to_date.rb
@@ -769,11 +772,11 @@ files:
769
772
  - lib/more/facets/synchash.rb
770
773
  - lib/more/facets/timer.rb
771
774
  - lib/more/facets/times.rb
772
- - lib/more/facets/tracepoint.rb
773
775
  - lib/more/facets/tuple.rb
774
776
  - lib/more/facets/typecast.rb
775
777
  - lib/more/facets/uninheritable.rb
776
778
  - lib/more/facets/uploadutils.rb
779
+ - lib/more/facets/validation.rb
777
780
  - lib/more/facets/version.rb
778
781
  - lib/more/facets/yaml.rb
779
782
  - lib/more/facets/ziputils.rb
@@ -783,7 +786,7 @@ files:
783
786
  - log/release.txt
784
787
  - log/todo.txt
785
788
  - meta
786
- - meta/facets-2.1.0.roll
789
+ - meta/facets-2.1.1.roll
787
790
  - meta/google_ad.html
788
791
  - meta/icli.yaml
789
792
  - meta/manifest.txt
@@ -808,6 +811,8 @@ files:
808
811
  - task/special
809
812
  - task/special/quickopts
810
813
  - task/stats
814
+ - task/svn
815
+ - task/svn/tag
811
816
  - task/syntax
812
817
  - task/test
813
818
  - task/testeach
@@ -1,13 +0,0 @@
1
- require 'facets/functor'
2
-
3
- class NilClass
4
-
5
- # CREDIT Daniel DeLorme
6
-
7
- #
8
- def ergo
9
- @blackhole ||= Functor.new{ nil }
10
- @blackhole unless block_given?
11
- end
12
- end
13
-
@@ -1,194 +0,0 @@
1
- # TITLE:
2
- #
3
- # TracePoint
4
- #
5
- # SUMMARY:
6
- #
7
- # A TracePoint is a Binding with the addition event information.
8
- # And it's a better way to use set_trace_func.
9
- #
10
- # COPYRIGHT:
11
- #
12
- # Copyright (c) 2005 Thomas Sawyer
13
- #
14
- # LICENSE:
15
- #
16
- # Ruby License
17
- #
18
- # This module is free software. You may use, modify, and/or redistribute this
19
- # software under the same terms as Ruby.
20
- #
21
- # This program is distributed in the hope that it will be useful, but WITHOUT
22
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23
- # FOR A PARTICULAR PURPOSE.
24
- #
25
- # AUTHORS:
26
- #
27
- # - Thomas Sawyer
28
-
29
-
30
- require 'facets/binding'
31
-
32
-
33
- # = CodePoint
34
- #
35
- # This is the same as a Binding. Not really needed, but I like consistency :)
36
-
37
- CodePoint = Binding
38
-
39
- # = TracePoint
40
- #
41
- # A TracePoint is a Binding with the addition of event information.
42
- # Among other things, it functions very well as the join-point for
43
- # Event-based AOP.
44
- #
45
- # == Usage
46
- #
47
- # TracePoint.trace { |tp|
48
- # puts "#{tp.self.class}\t#{tp.called}\t#{tp.event}\t#{tp.return?}\t#{tp.back == tp.bind}"
49
- # }
50
- #
51
- # 1 + 1
52
- #
53
- # produces
54
- #
55
- # Class trace return true false
56
- # Object line false false
57
- # Fixnum + c-call false false
58
- # Fixnum + c-return false false
59
- #
60
- # == Notes
61
- #
62
- # You can't subclass Binding, so we delegate (which is better anyway).
63
-
64
- class TracePoint #< Codepoint
65
-
66
- # -- class ---------------------
67
- class << self
68
-
69
- @@active = false
70
-
71
- def active ; @@active ; end
72
-
73
- def active=(x)
74
- @@active = x ? true : false
75
- unless @@active
76
- set_trace_func nil
77
- end
78
- end
79
-
80
- # Trace execution using a TracePoint.
81
- def trace # :yield:
82
- if active
83
- bb_stack = []
84
- set_trace_func proc{ |e, f, l, m, b, k|
85
- #(p e, f, l, m, b, k, @@bb_stack; puts "---") if $DEBUG
86
- if ['call','c-call','class'].include?(e)
87
- bb_stack << b
88
- elsif ['return','c-return','end'].include?(e)
89
- bb = bb_stack.pop
90
- end
91
- b = bb if ! b # this sucks!
92
- tp = TracePoint.new(e,m,b,bb)
93
- yield(tp)
94
- }
95
- end
96
- end
97
-
98
- end #class
99
-
100
- # -- instance -------------------
101
-
102
- attr_accessor :event, :binding, :back_binding
103
-
104
- # Until Ruby has a built-in way to get the name of the calling method
105
- # that information must be passed into the TracePoint.
106
- def initialize( event, method, bind, back_binding=bind )
107
- @event = event
108
- @method = method
109
- @binding = bind
110
- @back_binding = back_binding
111
- end
112
-
113
- # shorthand for binding
114
- def bind ; @binding ; end
115
-
116
- # shorthand for back_binding
117
- def back ; @back_binding ; end
118
-
119
- # Delegates "self" to the binding which
120
- # in turn delegates the binding object.
121
- def self ; @binding.self ; end
122
-
123
- # Returns the name of the event's method.
124
- # This could delegate to the binding if Ruby had
125
- # an internal way to retrieve the current method name.
126
- def callee ; @method ; end
127
- #def method ; @method ; end # TODO Conflict with Kernel#method?
128
- alias_method( :called, :callee ) # TODO deprecate
129
- alias_method( :method_name, :called ) # TODO deprecate
130
-
131
- # delegate to binding
132
- #def method_missing(meth, *args, &blk)
133
- # @binding.send(meth, *args, &blk)
134
- #end
135
-
136
- ### methods for working with events
137
-
138
- EVENT_MAP = {
139
- :all => ['call', 'c-call', 'return', 'c-return', 'line', 'class', 'end', 'raise'],
140
- :before => ['call', 'c-call'],
141
- :after => ['return', 'c-return'],
142
- :call => ['call'],
143
- :return => ['return'],
144
- :ccall => ['c-call'],
145
- :creturn => ['c-return'],
146
- :line => ['line'],
147
- :class => ['class'],
148
- :end => ['end'],
149
- :raise => ['raise']
150
- }
151
- def event_map(e) ; EVENT_MAP[e] ; end
152
-
153
- # Is the trace point defined or undefined?
154
- def event? ; !! @event ; end
155
- def eventless? ; ! @event ; end
156
-
157
- # For use in case conditions
158
- def ===(e)
159
- EVENT_MAP[e].include?(@event)
160
- end
161
-
162
- # Creates an <event>? method for each of the above event mappings.
163
- EVENT_MAP.each_pair { |m,v|
164
- define_method( "#{m}?" ){ v.include?(@event) }
165
- }
166
-
167
- end
168
-
169
-
170
-
171
- # _____ _
172
- # |_ _|__ ___| |_
173
- # | |/ _ \/ __| __|
174
- # | | __/\__ \ |_
175
- # |_|\___||___/\__|
176
- #
177
-
178
- # TODO
179
-
180
- =begin #test
181
-
182
- # Note: TracePoint will probably prove tricky to test, since
183
- # manipulating set_trace_func tends to wreak havoc on errors,
184
- # the call stack, and so on.
185
-
186
- TracePoint.active = true
187
-
188
- TracePoint.trace { |tp|
189
- puts "#{tp.self.class}\t#{tp.called}\t#{tp.event}\t#{tp.return?}\t#{tp.back == tp.bind}"
190
- }
191
-
192
- 1 + 1
193
-
194
- =end