monetra-ruby 0.0.6

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 (93) hide show
  1. data/Rakefile +35 -0
  2. data/lib/monetra.rb +239 -0
  3. data/lib/monetra/active_support.rb +42 -0
  4. data/lib/monetra/active_support/binding_of_caller.rb +84 -0
  5. data/lib/monetra/active_support/breakpoint.rb +523 -0
  6. data/lib/monetra/active_support/caching_tools.rb +62 -0
  7. data/lib/monetra/active_support/clean_logger.rb +38 -0
  8. data/lib/monetra/active_support/core_ext.rb +1 -0
  9. data/lib/monetra/active_support/core_ext/array.rb +7 -0
  10. data/lib/monetra/active_support/core_ext/array/conversions.rb +72 -0
  11. data/lib/monetra/active_support/core_ext/array/grouping.rb +46 -0
  12. data/lib/monetra/active_support/core_ext/bigdecimal.rb +3 -0
  13. data/lib/monetra/active_support/core_ext/bigdecimal/formatting.rb +7 -0
  14. data/lib/monetra/active_support/core_ext/blank.rb +50 -0
  15. data/lib/monetra/active_support/core_ext/cgi.rb +5 -0
  16. data/lib/monetra/active_support/core_ext/cgi/escape_skipping_slashes.rb +14 -0
  17. data/lib/monetra/active_support/core_ext/class.rb +3 -0
  18. data/lib/monetra/active_support/core_ext/class/attribute_accessors.rb +44 -0
  19. data/lib/monetra/active_support/core_ext/class/inheritable_attributes.rb +115 -0
  20. data/lib/monetra/active_support/core_ext/class/removal.rb +24 -0
  21. data/lib/monetra/active_support/core_ext/date.rb +6 -0
  22. data/lib/monetra/active_support/core_ext/date/conversions.rb +39 -0
  23. data/lib/monetra/active_support/core_ext/enumerable.rb +62 -0
  24. data/lib/monetra/active_support/core_ext/exception.rb +33 -0
  25. data/lib/monetra/active_support/core_ext/hash.rb +13 -0
  26. data/lib/monetra/active_support/core_ext/hash/conversions.rb +148 -0
  27. data/lib/monetra/active_support/core_ext/hash/diff.rb +11 -0
  28. data/lib/monetra/active_support/core_ext/hash/indifferent_access.rb +88 -0
  29. data/lib/monetra/active_support/core_ext/hash/keys.rb +53 -0
  30. data/lib/monetra/active_support/core_ext/hash/reverse_merge.rb +25 -0
  31. data/lib/monetra/active_support/core_ext/integer.rb +7 -0
  32. data/lib/monetra/active_support/core_ext/integer/even_odd.rb +24 -0
  33. data/lib/monetra/active_support/core_ext/integer/inflections.rb +15 -0
  34. data/lib/monetra/active_support/core_ext/kernel.rb +4 -0
  35. data/lib/monetra/active_support/core_ext/kernel/agnostics.rb +11 -0
  36. data/lib/monetra/active_support/core_ext/kernel/daemonizing.rb +15 -0
  37. data/lib/monetra/active_support/core_ext/kernel/reporting.rb +51 -0
  38. data/lib/monetra/active_support/core_ext/kernel/requires.rb +24 -0
  39. data/lib/monetra/active_support/core_ext/load_error.rb +38 -0
  40. data/lib/monetra/active_support/core_ext/logger.rb +16 -0
  41. data/lib/monetra/active_support/core_ext/module.rb +7 -0
  42. data/lib/monetra/active_support/core_ext/module/aliasing.rb +57 -0
  43. data/lib/monetra/active_support/core_ext/module/attr_internal.rb +31 -0
  44. data/lib/monetra/active_support/core_ext/module/attribute_accessors.rb +44 -0
  45. data/lib/monetra/active_support/core_ext/module/delegation.rb +41 -0
  46. data/lib/monetra/active_support/core_ext/module/inclusion.rb +11 -0
  47. data/lib/monetra/active_support/core_ext/module/introspection.rb +21 -0
  48. data/lib/monetra/active_support/core_ext/module/loading.rb +13 -0
  49. data/lib/monetra/active_support/core_ext/name_error.rb +20 -0
  50. data/lib/monetra/active_support/core_ext/numeric.rb +7 -0
  51. data/lib/monetra/active_support/core_ext/numeric/bytes.rb +44 -0
  52. data/lib/monetra/active_support/core_ext/numeric/time.rb +72 -0
  53. data/lib/monetra/active_support/core_ext/object.rb +2 -0
  54. data/lib/monetra/active_support/core_ext/object/extending.rb +47 -0
  55. data/lib/monetra/active_support/core_ext/object/misc.rb +34 -0
  56. data/lib/monetra/active_support/core_ext/pathname.rb +7 -0
  57. data/lib/monetra/active_support/core_ext/pathname/clean_within.rb +14 -0
  58. data/lib/monetra/active_support/core_ext/proc.rb +12 -0
  59. data/lib/monetra/active_support/core_ext/range.rb +5 -0
  60. data/lib/monetra/active_support/core_ext/range/conversions.rb +21 -0
  61. data/lib/monetra/active_support/core_ext/string.rb +13 -0
  62. data/lib/monetra/active_support/core_ext/string/access.rb +58 -0
  63. data/lib/monetra/active_support/core_ext/string/conversions.rb +19 -0
  64. data/lib/monetra/active_support/core_ext/string/inflections.rb +153 -0
  65. data/lib/monetra/active_support/core_ext/string/iterators.rb +17 -0
  66. data/lib/monetra/active_support/core_ext/string/starts_ends_with.rb +20 -0
  67. data/lib/monetra/active_support/core_ext/symbol.rb +12 -0
  68. data/lib/monetra/active_support/core_ext/time.rb +7 -0
  69. data/lib/monetra/active_support/core_ext/time/calculations.rb +188 -0
  70. data/lib/monetra/active_support/core_ext/time/conversions.rb +36 -0
  71. data/lib/monetra/active_support/dependencies.rb +187 -0
  72. data/lib/monetra/active_support/deprecation.rb +106 -0
  73. data/lib/monetra/active_support/inflections.rb +53 -0
  74. data/lib/monetra/active_support/inflector.rb +179 -0
  75. data/lib/monetra/active_support/json.rb +37 -0
  76. data/lib/monetra/active_support/json/encoders.rb +25 -0
  77. data/lib/monetra/active_support/json/encoders/core.rb +65 -0
  78. data/lib/monetra/active_support/option_merger.rb +25 -0
  79. data/lib/monetra/active_support/ordered_options.rb +50 -0
  80. data/lib/monetra/active_support/reloadable.rb +30 -0
  81. data/lib/monetra/active_support/values/time_zone.rb +180 -0
  82. data/lib/monetra/active_support/vendor/builder.rb +13 -0
  83. data/lib/monetra/active_support/vendor/builder/blankslate.rb +63 -0
  84. data/lib/monetra/active_support/vendor/builder/xchar.rb +112 -0
  85. data/lib/monetra/active_support/vendor/builder/xmlbase.rb +145 -0
  86. data/lib/monetra/active_support/vendor/builder/xmlevents.rb +63 -0
  87. data/lib/monetra/active_support/vendor/builder/xmlmarkup.rb +328 -0
  88. data/lib/monetra/active_support/vendor/flexmock.rb +84 -0
  89. data/lib/monetra/active_support/vendor/xml_simple.rb +1019 -0
  90. data/lib/monetra/active_support/version.rb +9 -0
  91. data/lib/monetra/active_support/whiny_nil.rb +38 -0
  92. data/test/test.rb +21 -0
  93. metadata +167 -0
@@ -0,0 +1,17 @@
1
+ require 'strscan'
2
+
3
+ module ActiveSupport #:nodoc:
4
+ module CoreExtensions #:nodoc:
5
+ module String #:nodoc:
6
+ # Custom string iterators
7
+ module Iterators
8
+ # Yields a single-character string for each character in the string.
9
+ # When $KCODE = 'UTF8', multi-byte characters are yielded appropriately.
10
+ def each_char
11
+ scanner, char = StringScanner.new(self), /./mu
12
+ loop { yield(scanner.scan(char) || break) }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module ActiveSupport #:nodoc:
2
+ module CoreExtensions #:nodoc:
3
+ module String #:nodoc:
4
+ # Additional string tests.
5
+ module StartsEndsWith
6
+ # Does the string start with the specified +prefix+?
7
+ def starts_with?(prefix)
8
+ prefix = prefix.to_s
9
+ self[0, prefix.length] == prefix
10
+ end
11
+
12
+ # Does the string end with the specified +suffix+?
13
+ def ends_with?(suffix)
14
+ suffix = suffix.to_s
15
+ self[-suffix.length, suffix.length] == suffix
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ class Symbol
2
+ # Turns the symbol into a simple proc, which is especially useful for enumerations. Examples:
3
+ #
4
+ # # The same as people.collect { |p| p.name }
5
+ # people.collect(&:name)
6
+ #
7
+ # # The same as people.select { |p| p.manager? }.collect { |p| p.salary }
8
+ # people.select(&:manager?).collect(&:salary)
9
+ def to_proc
10
+ Proc.new { |*args| args.shift.__send__(self, *args) }
11
+ end
12
+ 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,188 @@
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
+ def self.included(base) #:nodoc:
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # Return the number of days in the given month. If a year is given,
12
+ # February will return the correct number of days for leap years.
13
+ # Otherwise, this method will always report February as having 28
14
+ # days.
15
+ def days_in_month(month, year=nil)
16
+ if month == 2
17
+ !year.nil? && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) ? 29 : 28
18
+ elsif month <= 7
19
+ month % 2 == 0 ? 30 : 31
20
+ else
21
+ month % 2 == 0 ? 31 : 30
22
+ end
23
+ end
24
+ end
25
+
26
+ # Seconds since midnight: Time.now.seconds_since_midnight
27
+ def seconds_since_midnight
28
+ self.hour.hours + self.min.minutes + self.sec + (self.usec/1.0e+6)
29
+ end
30
+
31
+ # Returns a new Time where one or more of the elements have been changed according to the +options+ parameter. The time options
32
+ # (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
33
+ # minute is passed, then sec and usec is set to 0.
34
+ def change(options)
35
+ ::Time.send(
36
+ self.utc? ? :utc : :local,
37
+ options[:year] || self.year,
38
+ options[:month] || self.month,
39
+ options[:mday] || self.mday,
40
+ options[:hour] || self.hour,
41
+ options[:min] || (options[:hour] ? 0 : self.min),
42
+ options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
43
+ options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec)
44
+ )
45
+ end
46
+
47
+ # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with
48
+ # any of these keys: :months, :days, :years.
49
+ def advance(options)
50
+ d = ::Date.new(year + (options.delete(:years) || 0), month, day)
51
+ d = d >> options.delete(:months) if options[:months]
52
+ d = d + options.delete(:days) if options[:days]
53
+ change(options.merge(:year => d.year, :month => d.month, :mday => d.day))
54
+ end
55
+
56
+ # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
57
+ # Do not use this method in combination with x.months, use months_ago instead!
58
+ def ago(seconds)
59
+ seconds.until(self)
60
+ end
61
+
62
+ # Returns a new Time representing the time a number of seconds since the instance time, this is basically a wrapper around
63
+ #the Numeric extension. Do not use this method in combination with x.months, use months_since instead!
64
+ def since(seconds)
65
+ seconds.since(self)
66
+ end
67
+ alias :in :since
68
+
69
+ # Returns a new Time representing the time a number of specified months ago
70
+ def months_ago(months)
71
+ months_since(-months)
72
+ end
73
+
74
+ def months_since(months)
75
+ year, month, mday = self.year, self.month, self.mday
76
+
77
+ month += months
78
+
79
+ # in case months is negative
80
+ while month < 1
81
+ month += 12
82
+ year -= 1
83
+ end
84
+
85
+ # in case months is positive
86
+ while month > 12
87
+ month -= 12
88
+ year += 1
89
+ end
90
+
91
+ max = ::Time.days_in_month(month, year)
92
+ mday = max if mday > max
93
+
94
+ change(:year => year, :month => month, :mday => mday)
95
+ end
96
+
97
+ # Returns a new Time representing the time a number of specified years ago
98
+ def years_ago(years)
99
+ change(:year => self.year - years)
100
+ end
101
+
102
+ def years_since(years)
103
+ change(:year => self.year + years)
104
+ end
105
+
106
+ # Short-hand for years_ago(1)
107
+ def last_year
108
+ years_ago(1)
109
+ end
110
+
111
+ # Short-hand for years_since(1)
112
+ def next_year
113
+ years_since(1)
114
+ end
115
+
116
+
117
+ # Short-hand for months_ago(1)
118
+ def last_month
119
+ months_ago(1)
120
+ end
121
+
122
+ # Short-hand for months_since(1)
123
+ def next_month
124
+ months_since(1)
125
+ end
126
+
127
+ # Returns a new Time representing the "start" of this week (Monday, 0:00)
128
+ def beginning_of_week
129
+ days_to_monday = self.wday!=0 ? self.wday-1 : 6
130
+ (self - days_to_monday.days).midnight
131
+ end
132
+ alias :monday :beginning_of_week
133
+ alias :at_beginning_of_week :beginning_of_week
134
+
135
+ # Returns a new Time representing the start of the given day in next week (default is Monday).
136
+ def next_week(day = :monday)
137
+ days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
138
+ since(1.week).beginning_of_week.since(days_into_week[day].day).change(:hour => 0)
139
+ end
140
+
141
+ # Returns a new Time representing the start of the day (0:00)
142
+ def beginning_of_day
143
+ (self - self.seconds_since_midnight).change(:usec => 0)
144
+ end
145
+ alias :midnight :beginning_of_day
146
+ alias :at_midnight :beginning_of_day
147
+ alias :at_beginning_of_day :beginning_of_day
148
+
149
+ # Returns a new Time representing the start of the month (1st of the month, 0:00)
150
+ def beginning_of_month
151
+ #self - ((self.mday-1).days + self.seconds_since_midnight)
152
+ change(:mday => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
153
+ end
154
+ alias :at_beginning_of_month :beginning_of_month
155
+
156
+ # Returns a new Time representing the end of the month (last day of the month, 0:00)
157
+ def end_of_month
158
+ #self - ((self.mday-1).days + self.seconds_since_midnight)
159
+ last_day = ::Time.days_in_month( self.month, self.year )
160
+ change(:mday => last_day,:hour => 0, :min => 0, :sec => 0, :usec => 0)
161
+ end
162
+ alias :at_end_of_month :end_of_month
163
+
164
+ # Returns a new Time representing the start of the quarter (1st of january, april, july, october, 0:00)
165
+ def beginning_of_quarter
166
+ beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
167
+ end
168
+ alias :at_beginning_of_quarter :beginning_of_quarter
169
+
170
+ # Returns a new Time representing the start of the year (1st of january, 0:00)
171
+ def beginning_of_year
172
+ change(:month => 1,:mday => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
173
+ end
174
+ alias :at_beginning_of_year :beginning_of_year
175
+
176
+ # Convenience method which returns a new Time representing the time 1 day ago
177
+ def yesterday
178
+ self.ago(1.day)
179
+ end
180
+
181
+ # Convenience method which returns a new Time representing the time 1 day since the instance time
182
+ def tomorrow
183
+ self.since(1.day)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,36 @@
1
+ require 'date'
2
+ require 'time'
3
+
4
+ module ActiveSupport #:nodoc:
5
+ module CoreExtensions #:nodoc:
6
+ module Time #:nodoc:
7
+ # Getting times in different convenient string representations and other objects
8
+ module Conversions
9
+ DATE_FORMATS = {
10
+ :db => "%Y-%m-%d %H:%M:%S",
11
+ :short => "%d %b %H:%M",
12
+ :long => "%B %d, %Y %H:%M",
13
+ :rfc822 => "%a, %d %b %Y %H:%M:%S %z"
14
+ }
15
+
16
+ def self.included(klass)
17
+ klass.send(:alias_method, :to_default_s, :to_s)
18
+ klass.send(:alias_method, :to_s, :to_formatted_s)
19
+ end
20
+
21
+ def to_formatted_s(format = :default)
22
+ DATE_FORMATS[format] ? strftime(DATE_FORMATS[format]).strip : to_default_s
23
+ end
24
+
25
+ def to_date
26
+ ::Date.new(year, month, day)
27
+ end
28
+
29
+ # To be able to keep Dates and Times interchangeable on conversions
30
+ def to_time
31
+ self
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,187 @@
1
+ require 'set'
2
+ require File.dirname(__FILE__) + '/core_ext/module/attribute_accessors'
3
+ require File.dirname(__FILE__) + '/core_ext/load_error'
4
+ require File.dirname(__FILE__) + '/core_ext/kernel'
5
+
6
+ module Dependencies #:nodoc:
7
+ extend self
8
+
9
+ # Should we turn on Ruby warnings on the first load of dependent files?
10
+ mattr_accessor :warnings_on_first_load
11
+ self.warnings_on_first_load = false
12
+
13
+ # All files ever loaded.
14
+ mattr_accessor :history
15
+ self.history = Set.new
16
+
17
+ # All files currently loaded.
18
+ mattr_accessor :loaded
19
+ self.loaded = Set.new
20
+
21
+ # Should we load files or require them?
22
+ mattr_accessor :mechanism
23
+ self.mechanism = :load
24
+
25
+ def load?
26
+ mechanism == :load
27
+ end
28
+
29
+ def depend_on(file_name, swallow_load_errors = false)
30
+ require_or_load(file_name)
31
+ rescue LoadError
32
+ raise unless swallow_load_errors
33
+ end
34
+
35
+ def associate_with(file_name)
36
+ depend_on(file_name, true)
37
+ end
38
+
39
+ def clear
40
+ loaded.clear
41
+ end
42
+
43
+ def require_or_load(file_name)
44
+ file_name = $1 if file_name =~ /^(.*)\.rb$/
45
+ return if loaded.include?(file_name)
46
+
47
+ # Record that we've seen this file *before* loading it to avoid an
48
+ # infinite loop with mutual dependencies.
49
+ loaded << file_name
50
+
51
+ if load?
52
+ begin
53
+ # Enable warnings iff this file has not been loaded before and
54
+ # warnings_on_first_load is set.
55
+ if !warnings_on_first_load or history.include?(file_name)
56
+ load "#{file_name}.rb"
57
+ else
58
+ enable_warnings { load "#{file_name}.rb" }
59
+ end
60
+ rescue
61
+ loaded.delete file_name
62
+ raise
63
+ end
64
+ else
65
+ require file_name
66
+ end
67
+
68
+ # Record history *after* loading so first load gets warnings.
69
+ history << file_name
70
+ end
71
+
72
+ # Return the a constant path for the provided parent and constant name
73
+ def constant_path_for(mod, name)
74
+ ([Object, Kernel].include? mod) ? name.to_s : "#{mod}::#{name}"
75
+ end
76
+
77
+ class LoadingModule
78
+ # Old style environment.rb referenced this method directly. Please note, it doesn't
79
+ # actualy *do* anything any more.
80
+ def self.root(*args)
81
+ if defined?(RAILS_DEFAULT_LOGGER)
82
+ RAILS_DEFAULT_LOGGER.warn "Your environment.rb uses the old syntax, it may not continue to work in future releases."
83
+ RAILS_DEFAULT_LOGGER.warn "For upgrade instructions please see: http://manuals.rubyonrails.com/read/book/19"
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
90
+ Object.send(:define_method, :require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
91
+ Object.send(:define_method, :require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
92
+
93
+ class Module #:nodoc:
94
+ # Rename the original handler so we can chain it to the new one
95
+ alias :rails_original_const_missing :const_missing
96
+
97
+ # Use const_missing to autoload associations so we don't have to
98
+ # require_association when using single-table inheritance.
99
+ def const_missing(class_id)
100
+ file_name = class_id.to_s.demodulize.underscore
101
+ file_path = as_load_path.empty? ? file_name : "#{as_load_path}/#{file_name}"
102
+ begin
103
+ require_dependency(file_path)
104
+ brief_name = self == Object ? '' : "#{name}::"
105
+ raise NameError.new("uninitialized constant #{brief_name}#{class_id}") unless const_defined?(class_id)
106
+ return const_get(class_id)
107
+ rescue MissingSourceFile => e
108
+ # Re-raise the error if it does not concern the file we were trying to load.
109
+ raise unless e.is_missing? file_path
110
+
111
+ # Look for a directory in the load path that we ought to load.
112
+ if $LOAD_PATH.any? { |base| File.directory? "#{base}/#{file_path}" }
113
+ mod = Module.new
114
+ const_set class_id, mod # Create the new module
115
+ return mod
116
+ end
117
+
118
+ # Attempt to access the name from the parent, unless we don't have a valid
119
+ # parent, or the constant is already defined in the parent. If the latter
120
+ # is the case, then we are being queried via self::class_id, and we should
121
+ # avoid returning the constant from the parent if possible.
122
+ if parent && parent != self && ! parents.any? { |p| p.const_defined?(class_id) }
123
+ suppress(NameError) do
124
+ return parent.send(:const_missing, class_id)
125
+ end
126
+ end
127
+
128
+ qualified_name = Dependencies.constant_path_for self, class_id
129
+ raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
130
+ end
131
+ end
132
+ end
133
+
134
+ class Class
135
+ def const_missing(class_id)
136
+ if [Object, Kernel].include?(self) || parent == self
137
+ super
138
+ else
139
+ begin
140
+ parent.send :const_missing, class_id
141
+ rescue NameError => e
142
+ # Make sure that the name we are missing is the one that caused the error
143
+ parent_qualified_name = Dependencies.constant_path_for parent, class_id
144
+ raise unless e.missing_name? parent_qualified_name
145
+ qualified_name = Dependencies.constant_path_for self, class_id
146
+ raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ class Object #:nodoc:
153
+ def load(file, *extras)
154
+ super(file, *extras)
155
+ rescue Object => exception
156
+ exception.blame_file! file
157
+ raise
158
+ end
159
+
160
+ def require(file, *extras)
161
+ super(file, *extras)
162
+ rescue Object => exception
163
+ exception.blame_file! file
164
+ raise
165
+ end
166
+ end
167
+
168
+ # Add file-blaming to exceptions
169
+ class Exception #:nodoc:
170
+ def blame_file!(file)
171
+ (@blamed_files ||= []).unshift file
172
+ end
173
+
174
+ def blamed_files
175
+ @blamed_files ||= []
176
+ end
177
+
178
+ def describe_blame
179
+ return nil if blamed_files.empty?
180
+ "This error occurred while loading the following files:\n #{blamed_files.join "\n "}"
181
+ end
182
+
183
+ def copy_blame!(exc)
184
+ @blamed_files = exc.blamed_files.clone
185
+ self
186
+ end
187
+ end