activesupport 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/string/inflections'
2
+
3
+ class String #:nodoc:
4
+ include ActiveSupport::CoreExtensions::String::Inflections
5
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/../../inflector'
2
+ module ActiveSupport #:nodoc:
3
+ module CoreExtensions #:nodoc:
4
+ module String #:nodoc:
5
+ # Makes it possible to do "posts".singularize that returns "post" and "MegaCoolClass".underscore that returns "mega_cool_class".
6
+ module Inflections
7
+ def pluralize
8
+ Inflector.pluralize(self)
9
+ end
10
+
11
+ def singularize
12
+ Inflector.singularize(self)
13
+ end
14
+
15
+ def camelize
16
+ Inflector.camelize(self)
17
+ end
18
+
19
+ def underscore
20
+ Inflector.underscore(self)
21
+ end
22
+
23
+ def demodulize
24
+ Inflector.demodulize(self)
25
+ end
26
+
27
+ def tableize
28
+ Inflector.tableize(self)
29
+ end
30
+
31
+ def classify
32
+ Inflector.classify(self)
33
+ end
34
+
35
+ def humanize
36
+ Inflector.humanize(self)
37
+ end
38
+
39
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
40
+ Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
41
+ end
42
+
43
+ def constantize
44
+ Inflector.constantize(self)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/time/calculations'
2
+ require File.dirname(__FILE__) + '/time/conversions'
3
+
4
+ class Time#:nodoc:
5
+ include ActiveSupport::CoreExtensions::Time::Calculations
6
+ include ActiveSupport::CoreExtensions::Time::Conversions
7
+ end
@@ -0,0 +1,133 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module Time #:nodoc:
4
+ # Enables the use of time calculations within Time itself
5
+ module Calculations
6
+ # Seconds since midnight: Time.now.seconds_since_midnight
7
+ def seconds_since_midnight
8
+ self.hour.hours + self.min.minutes + self.sec + (self.usec/1.0e+6)
9
+ end
10
+
11
+ # Returns a new Time where one or more of the elements have been changed according to the +options+ parameter. The time options
12
+ # (hour, minute, sec, usec) reset cascadingly, so if only the hour is passed, then minute, sec, and usec is set to 0. If the hour and
13
+ # minute is passed, then sec and usec is set to 0.
14
+ def change(options)
15
+ ::Time.send(
16
+ self.utc? ? :utc : :local,
17
+ options[:year] || self.year,
18
+ options[:month] || self.month,
19
+ options[:mday] || self.mday,
20
+ options[:hour] || self.hour,
21
+ options[:min] || (options[:hour] ? 0 : self.min),
22
+ options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
23
+ options[:usec] || ((options[:hour] || options[:min] || options[:usec]) ? 0 : self.usec)
24
+ )
25
+ end
26
+
27
+ # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
28
+ # Do not use this method in combination with x.months, use months_ago instead!
29
+ def ago(seconds)
30
+ seconds.until(self)
31
+ end
32
+
33
+ # Returns a new Time representing the time a number of seconds since the instance time, this is basically a wrapper around
34
+ #the Numeric extension. Do not use this method in combination with x.months, use months_since instead!
35
+ def since(seconds)
36
+ seconds.since(self)
37
+ end
38
+ alias :in :since
39
+
40
+ # Returns a new Time representing the time a number of specified months ago
41
+ def months_ago(months)
42
+ if months >= self.month
43
+ change(:year => self.year - 1, :month => 12).months_ago(months - self.month)
44
+ else
45
+ change(:year => self.year, :month => self.month - months)
46
+ end
47
+ end
48
+
49
+ def months_since(months)
50
+ if months + self.month > 12
51
+ change(:year => self.year + 1, :month => 1).months_since(months - (self.month == 1 ? 12 : (self.month + 1)))
52
+ else
53
+ change(:year => self.year, :month => self.month + months)
54
+ end
55
+ end
56
+
57
+ # Returns a new Time representing the time a number of specified years ago
58
+ def years_ago(years)
59
+ change(:year => self.year - years)
60
+ end
61
+
62
+ def years_since(years)
63
+ change(:year => self.year + years)
64
+ end
65
+
66
+ # Short-hand for months_ago(1)
67
+ def last_year
68
+ years_since(1)
69
+ end
70
+
71
+ # Short-hand for months_since(1)
72
+ def next_year
73
+ years_since(1)
74
+ end
75
+
76
+
77
+ # Short-hand for months_ago(1)
78
+ def last_month
79
+ months_ago(1)
80
+ end
81
+
82
+ # Short-hand for months_since(1)
83
+ def next_month
84
+ months_since(1)
85
+ end
86
+
87
+ # Returns a new Time representing the "start" of this week (Monday, 0:00)
88
+ def beginning_of_week
89
+ (self - self.wday.days).midnight + 1.day
90
+ end
91
+ alias :monday :beginning_of_week
92
+ alias :at_beginning_of_week :beginning_of_week
93
+
94
+ # Returns a new Time representing the start of the given day in next week (default is Monday).
95
+ def next_week(day = :monday)
96
+ days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
97
+ since(1.week).beginning_of_week.since(days_into_week[day].day).change(:hour => 0)
98
+ end
99
+
100
+ # Returns a new Time representing the start of the day (0:00)
101
+ def beginning_of_day
102
+ self - self.seconds_since_midnight
103
+ end
104
+ alias :midnight :beginning_of_day
105
+ alias :at_midnight :beginning_of_day
106
+ alias :at_beginning_of_day :beginning_of_day
107
+
108
+ # Returns a new Time representing the start of the month (1st of the month, 0:00)
109
+ def beginning_of_month
110
+ #self - ((self.mday-1).days + self.seconds_since_midnight)
111
+ change(:mday => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
112
+ end
113
+ alias :at_beginning_of_month :beginning_of_month
114
+
115
+ # Returns a new Time representing the start of the year (1st of january, 0:00)
116
+ def beginning_of_year
117
+ change(:month => 1,:mday => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
118
+ end
119
+ alias :at_beginning_of_year :beginning_of_year
120
+
121
+ # Convenience method which returns a new Time representing the time 1 day ago
122
+ def yesterday
123
+ self.ago(1.day)
124
+ end
125
+
126
+ # Convenience method which returns a new Time representing the time 1 day since the instance time
127
+ def tomorrow
128
+ self.since(1.day)
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,34 @@
1
+ require 'date'
2
+
3
+ module ActiveSupport #:nodoc:
4
+ module CoreExtensions #:nodoc:
5
+ module Time #:nodoc:
6
+ # Getting times in different convenient string representations and other objects
7
+ module Conversions
8
+ def self.append_features(klass)
9
+ super
10
+ klass.send(:alias_method, :to_default_s, :to_s)
11
+ klass.send(:alias_method, :to_s, :to_formatted_s)
12
+ end
13
+
14
+ def to_formatted_s(format = :default)
15
+ case format
16
+ when :default then to_default_s
17
+ when :db then strftime("%Y-%m-%d %H:%M:%S")
18
+ when :short then strftime("%e %b %H:%M").strip
19
+ when :long then strftime("%B %e, %Y %H:%M").strip
20
+ end
21
+ end
22
+
23
+ def to_date
24
+ ::Date.new(year, month, day)
25
+ end
26
+
27
+ # To be able to keep Dates and Times interchangeable on conversions
28
+ def to_time
29
+ self
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,212 @@
1
+ require File.dirname(__FILE__) + '/module_attribute_accessors'
2
+
3
+ module Dependencies
4
+ extend self
5
+
6
+ @@loaded = [ ]
7
+ mattr_accessor :loaded
8
+
9
+ @@mechanism = :load
10
+ mattr_accessor :mechanism
11
+
12
+ def load?
13
+ mechanism == :load
14
+ end
15
+
16
+ def depend_on(file_name, swallow_load_errors = false)
17
+ if !loaded.include?(file_name)
18
+ loaded << file_name
19
+
20
+ begin
21
+ require_or_load(file_name)
22
+ rescue LoadError
23
+ raise unless swallow_load_errors
24
+ rescue Object => e
25
+ raise ScriptError, "#{e.message}"
26
+ end
27
+ end
28
+ end
29
+
30
+ def associate_with(file_name)
31
+ depend_on(file_name, true)
32
+ end
33
+
34
+ def clear
35
+ self.loaded = [ ]
36
+ end
37
+
38
+ def require_or_load(file_name)
39
+ load? ? load("#{file_name}.rb") : require(file_name)
40
+ end
41
+
42
+ def remove_subclasses_for(*classes)
43
+ classes.each { |klass| klass.remove_subclasses }
44
+ end
45
+
46
+ # LoadingModules implement namespace-safe dynamic loading.
47
+ # They support automatic loading via const_missing, allowing contained items to be automatically
48
+ # loaded when required. No extra syntax is required, as expressions such as Controller::Admin::UserController
49
+ # load the relavent files automatically.
50
+ #
51
+ # Ruby-style modules are supported, as a folder named 'submodule' will load 'submodule.rb' when available.
52
+ class LoadingModule < Module
53
+ attr_reader :path
54
+ attr_reader :root
55
+
56
+ def self.root(*load_paths)
57
+ RootLoadingModule.new(*load_paths)
58
+ end
59
+
60
+ def initialize(root, path=[])
61
+ @path = path.clone.freeze
62
+ @root = root
63
+ end
64
+
65
+ def load_paths() self.root.load_paths end
66
+
67
+ # Load missing constants if possible.
68
+ def const_missing(name)
69
+ const_load!(name) ? const_get(name) : super(name)
70
+ end
71
+
72
+ # Load the controller class or a parent module.
73
+ def const_load!(name, file_name = nil)
74
+ path = self.path + [file_name || name]
75
+
76
+ load_paths.each do |load_path|
77
+ fs_path = load_path.filesystem_path(path)
78
+ next unless fs_path
79
+
80
+ if File.directory?(fs_path)
81
+ self.const_set name, LoadingModule.new(self.root, self.path + [name])
82
+ break
83
+ elsif File.file?(fs_path)
84
+ self.root.load_file!(fs_path)
85
+ break
86
+ end
87
+ end
88
+
89
+ return self.const_defined?(name)
90
+ end
91
+
92
+ # Is this name present or loadable?
93
+ # This method is used by Routes to find valid controllers.
94
+ def const_available?(name)
95
+ self.const_defined?(name) || load_paths.any? {|lp| lp.filesystem_path(path + [name])}
96
+ end
97
+ end
98
+
99
+ class RootLoadingModule < LoadingModule
100
+ attr_reader :load_paths
101
+
102
+ def initialize(*paths)
103
+ @load_paths = paths.flatten.collect {|p| p.kind_of?(ConstantLoadPath) ? p : ConstantLoadPath.new(p)}
104
+ end
105
+
106
+ def root() self end
107
+
108
+ def path() [] end
109
+
110
+ # Load the source file at the given file path
111
+ def load_file!(file_path)
112
+ begin root.module_eval(IO.read(file_path), file_path, 1)
113
+ rescue Object => exception
114
+ exception.blame_file! file_path
115
+ raise
116
+ end
117
+ end
118
+
119
+ # Erase all items in this module
120
+ def clear!
121
+ constants.each do |name|
122
+ Object.send(:remove_const, name) if Object.const_defined?(name) && self.path.empty?
123
+ self.send(:remove_const, name)
124
+ end
125
+ end
126
+ end
127
+
128
+ # This object defines a path from which Constants can be loaded.
129
+ class ConstantLoadPath
130
+ # Create a new load path with the filesystem path
131
+ def initialize(root) @root = root end
132
+
133
+ # Return nil if the path does not exist, or the path to a directory
134
+ # if the path leads to a module, or the path to a file if it leads to an object.
135
+ def filesystem_path(path, allow_module=true)
136
+ fs_path = [@root]
137
+ fs_path += path[0..-2].collect {|name| const_name_to_module_name name}
138
+
139
+ if allow_module
140
+ result = File.join(fs_path, const_name_to_module_name(path.last))
141
+ return result if File.directory? result # Return the module path if one exists
142
+ end
143
+
144
+ result = File.join(fs_path, const_name_to_file_name(path.last))
145
+
146
+ return File.file?(result) ? result : nil
147
+ end
148
+
149
+ def const_name_to_file_name(name)
150
+ name.to_s.underscore + '.rb'
151
+ end
152
+
153
+ def const_name_to_module_name(name)
154
+ name.to_s.underscore
155
+ end
156
+ end
157
+ end
158
+
159
+ Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
160
+ Object.send(:define_method, :require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
161
+ Object.send(:define_method, :require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
162
+
163
+ class Object #:nodoc:
164
+ class << self
165
+ # Use const_missing to autoload associations so we don't have to
166
+ # require_association when using single-table inheritance.
167
+ def const_missing(class_id)
168
+ if Object.const_defined?(:Controllers) and Object::Controllers.const_available?(class_id)
169
+ return Object::Controllers.const_get(class_id)
170
+ end
171
+
172
+ begin
173
+ require_or_load(class_id.to_s.demodulize.underscore)
174
+ if Object.const_defined?(class_id) then return Object.const_get(class_id) else raise LoadError end
175
+ rescue LoadError
176
+ raise NameError, "uninitialized constant #{class_id}"
177
+ end
178
+ end
179
+ end
180
+
181
+ def load(file, *extras)
182
+ begin super(file, *extras)
183
+ rescue Object => exception
184
+ exception.blame_file! file
185
+ raise
186
+ end
187
+ end
188
+
189
+ def require(file, *extras)
190
+ begin super(file, *extras)
191
+ rescue Object => exception
192
+ exception.blame_file! file
193
+ raise
194
+ end
195
+ end
196
+ end
197
+
198
+ # Add file-blaming to exceptions
199
+ class Exception
200
+ def blame_file!(file)
201
+ (@blamed_files ||= []).unshift file
202
+ end
203
+
204
+ def blamed_files
205
+ @blamed_files ||= []
206
+ end
207
+
208
+ def describe_blame
209
+ return nil if blamed_files.empty?
210
+ "This error occured while loading the following files:\n #{blamed_files.join "\n "}"
211
+ end
212
+ end
@@ -0,0 +1,93 @@
1
+ # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
2
+ # and class names to foreign keys.
3
+ module Inflector
4
+ extend self
5
+
6
+ def pluralize(word)
7
+ result = word.to_s.dup
8
+ plural_rules.each do |(rule, replacement)|
9
+ break if result.gsub!(rule, replacement)
10
+ end
11
+ return result
12
+ end
13
+
14
+ def singularize(word)
15
+ result = word.to_s.dup
16
+ singular_rules.each do |(rule, replacement)|
17
+ break if result.gsub!(rule, replacement)
18
+ end
19
+ return result
20
+ end
21
+
22
+ def camelize(lower_case_and_underscored_word)
23
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
24
+ end
25
+
26
+ def underscore(camel_cased_word)
27
+ camel_cased_word.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
28
+ end
29
+
30
+ def humanize(lower_case_and_underscored_word)
31
+ lower_case_and_underscored_word.to_s.gsub(/_/, " ").capitalize
32
+ end
33
+
34
+ def demodulize(class_name_in_module)
35
+ class_name_in_module.to_s.gsub(/^.*::/, '')
36
+ end
37
+
38
+ def tableize(class_name)
39
+ pluralize(underscore(class_name))
40
+ end
41
+
42
+ def classify(table_name)
43
+ camelize(singularize(table_name))
44
+ end
45
+
46
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
47
+ Inflector.underscore(Inflector.demodulize(class_name)) +
48
+ (separate_class_name_and_id_with_underscore ? "_id" : "id")
49
+ end
50
+
51
+ def constantize(camel_cased_word)
52
+ camel_cased_word.split("::").inject(Object) do |final_type, part|
53
+ final_type = final_type.const_get(part)
54
+ end
55
+ end
56
+
57
+ private
58
+ def plural_rules #:doc:
59
+ [
60
+ [/(x|ch|ss|sh)$/, '\1es'], # search, switch, fix, box, process, address
61
+ [/series$/, '\1series'],
62
+ [/([^aeiouy]|qu)ies$/, '\1y'],
63
+ [/([^aeiouy]|qu)y$/, '\1ies'], # query, ability, agency
64
+ [/(?:([^f])fe|([lr])f)$/, '\1\2ves'], # half, safe, wife
65
+ [/sis$/, 'ses'], # basis, diagnosis
66
+ [/([ti])um$/, '\1a'], # datum, medium
67
+ [/person$/, 'people'], # person, salesperson
68
+ [/man$/, 'men'], # man, woman, spokesman
69
+ [/child$/, 'children'], # child
70
+ [/s$/, 's'], # no change (compatibility)
71
+ [/$/, 's']
72
+ ]
73
+ end
74
+
75
+ def singular_rules #:doc:
76
+ [
77
+ [/(x|ch|ss)es$/, '\1'],
78
+ [/movies$/, 'movie'],
79
+ [/series$/, 'series'],
80
+ [/([^aeiouy]|qu)ies$/, '\1y'],
81
+ [/([lr])ves$/, '\1f'],
82
+ [/([^f])ves$/, '\1fe'],
83
+ [/(analy|ba|diagno|parenthe|progno|synop|the)ses$/, '\1sis'],
84
+ [/([ti])a$/, '\1um'],
85
+ [/people$/, 'person'],
86
+ [/men$/, 'man'],
87
+ [/status$/, 'status'],
88
+ [/children$/, 'child'],
89
+ [/news$/, 'news'],
90
+ [/s$/, '']
91
+ ]
92
+ end
93
+ end