facets 2.1.0 → 2.1.1

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.
@@ -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