rails-units 1.3.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.
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ 2006-10-02 Currency handling remains to be implemented well
2
+ 2011-04-23 Refactor caching
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.3.1
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require "ruby_units/version"
3
+ require "ruby_units/cache"
4
+ require 'ruby_units/array'
5
+ require 'ruby_units/date'
6
+ require 'ruby_units/time'
7
+ require 'ruby_units/math'
8
+ require 'ruby_units/numeric'
9
+ require 'ruby_units/object'
10
+ require 'ruby_units/string'
11
+ require 'ruby_units/unit_definitions'
12
+ require 'ruby_units/unit'
13
+ require 'ruby_units/fixnum'
14
+
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require "ruby_units/version"
3
+ require "ruby_units/cache"
4
+ require 'ruby_units/array'
5
+ require 'ruby_units/date'
6
+ require 'ruby_units/time'
7
+ require 'ruby_units/math'
8
+ require 'ruby_units/numeric'
9
+ require 'ruby_units/object'
10
+ require 'ruby_units/string'
11
+ require 'ruby_units/unit_definitions'
12
+ require 'ruby_units/unit'
13
+ require 'ruby_units/fixnum'
14
+
@@ -0,0 +1,9 @@
1
+ # make a unit from an array
2
+ # [1, 'mm'].unit => 1 mm
3
+ class Array
4
+ def to_unit(other = nil)
5
+ other ? Unit.new(self).to(other) : Unit.new(self)
6
+ end
7
+ alias :unit :to_unit
8
+ alias :u :to_unit
9
+ end
@@ -0,0 +1,20 @@
1
+ class Unit < Numeric
2
+ @@cached_units = {}
3
+
4
+ class Cache
5
+ def self.get(key = nil)
6
+ key.nil? ? @@cached_units : @@cached_units[key]
7
+ end
8
+
9
+ def self.set(key, value)
10
+ @@cached_units[key] = value
11
+ end
12
+
13
+ def self.clear
14
+ @@cached_units = {}
15
+ @@base_unit_cache = {}
16
+ Unit.new(1)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,53 @@
1
+ # Allow date objects to do offsets by a time unit
2
+ # Date.today + U"1 week" => gives today+1 week
3
+
4
+ require 'date'
5
+
6
+ class Date
7
+ alias :unit_date_add :+
8
+ def +(unit)
9
+ case unit
10
+ when Unit
11
+ unit = unit.to('d').round if ['y', 'decade', 'century'].include? unit.units
12
+ unit_date_add(unit.to('day').scalar)
13
+ else
14
+ unit_date_add(unit)
15
+ end
16
+ end
17
+
18
+
19
+ alias :unit_date_sub :-
20
+ def -(unit)
21
+ case unit
22
+ when Unit
23
+ unit = unit.to('d').round if ['y', 'decade', 'century'].include? unit.units
24
+ unit_date_sub(unit.to('day').scalar)
25
+ else
26
+ unit_date_sub(unit)
27
+ end
28
+ end
29
+
30
+ def to_unit(other = nil)
31
+ other ? Unit.new(self).to(other) : Unit.new(self)
32
+ end
33
+ alias :unit :to_unit
34
+
35
+ unless Date.instance_methods.include?(:to_time)
36
+ def to_time
37
+ Time.local(*ParseDate.parsedate(self.to_s))
38
+ end
39
+ end
40
+
41
+ alias :units_datetime_inspect :inspect
42
+ def inspect(raw = false)
43
+ return self.units_datetime_inspect if raw
44
+ self.to_s
45
+ end
46
+
47
+ unless Date.instance_methods.include?(:to_date)
48
+ def to_date
49
+ Date.civil(self.year, self.month, self.day)
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,20 @@
1
+ # this patch is necessary for ruby 1.8 because cases where
2
+ # Integers are divided by Units don't work quite right
3
+
4
+ if RUBY_VERSION < "1.9"
5
+ class Fixnum
6
+ alias quo_without_units quo
7
+
8
+ def quo_with_units(other)
9
+ case other
10
+ when Unit
11
+ self * other.inverse
12
+ else
13
+ quo_without_units(other)
14
+ end
15
+ end
16
+
17
+ alias quo quo_with_units
18
+ alias / quo_with_units
19
+ end
20
+ end
@@ -0,0 +1,101 @@
1
+ # Math will convert unit objects to radians and then attempt to use the value for
2
+ # trigonometric functions.
3
+ require 'mathn'
4
+
5
+ module Math
6
+
7
+ alias :unit_sqrt :sqrt
8
+ def sqrt(n)
9
+ if Unit === n
10
+ (n**(Rational(1,2))).to_unit
11
+ else
12
+ unit_sqrt(n)
13
+ end
14
+ end
15
+ module_function :unit_sqrt
16
+ module_function :sqrt
17
+
18
+ #:nocov:
19
+ if self.respond_to?(:cbrt)
20
+ alias :unit_cbrt :cbrt
21
+ def cbrt(n)
22
+ if Unit === n
23
+ (n**(Rational(1,3))).to_unit
24
+ else
25
+ unit_cbrt(n)
26
+ end
27
+ end
28
+ module_function :unit_cbrt
29
+ module_function :cbrt
30
+ end
31
+ #:nocov:
32
+
33
+ alias :unit_sin :sin
34
+ def sin(n)
35
+ Unit === n ? unit_sin(n.to('radian').scalar) : unit_sin(n)
36
+ end
37
+ module_function :unit_sin
38
+ module_function :sin
39
+
40
+ alias :unit_cos :cos
41
+ def cos(n)
42
+ Unit === n ? unit_cos(n.to('radian').scalar) : unit_cos(n)
43
+ end
44
+ module_function :unit_cos
45
+ module_function :cos
46
+
47
+ alias :unit_sinh :sinh
48
+ def sinh(n)
49
+ Unit === n ? unit_sinh(n.to('radian').scalar) : unit_sinh(n)
50
+ end
51
+ module_function :unit_sinh
52
+ module_function :sinh
53
+
54
+ alias :unit_cosh :cosh
55
+ def cosh(n)
56
+ Unit === n ? unit_cosh(n.to('radian').scalar) : unit_cosh(n)
57
+ end
58
+ module_function :unit_cosh
59
+ module_function :cosh
60
+
61
+ alias :unit_tan :tan
62
+ def tan(n)
63
+ Unit === n ? unit_tan(n.to('radian').scalar) : unit_tan(n)
64
+ end
65
+ module_function :tan
66
+ module_function :unit_tan
67
+
68
+ alias :unit_tanh :tanh
69
+ def tanh(n)
70
+ Unit === n ? unit_tanh(n.to('radian').scalar) : unit_tanh(n)
71
+ end
72
+ module_function :unit_tanh
73
+ module_function :tanh
74
+
75
+ alias :unit_hypot :hypot
76
+ # Convert parameters to consistent units and perform the function
77
+ def hypot(x,y)
78
+ if Unit === x && Unit === y
79
+ (x**2 + y**2)**(1/2)
80
+ else
81
+ unit_hypot(x,y)
82
+ end
83
+ end
84
+ module_function :unit_hypot
85
+ module_function :hypot
86
+
87
+ alias :unit_atan2 :atan2
88
+ def atan2(x,y)
89
+ case
90
+ when (x.is_a?(Unit) && y.is_a?(Unit)) && (x !~ y)
91
+ raise ArgumentError, "Incompatible Units"
92
+ when (x.is_a?(Unit) && y.is_a?(Unit)) && (x =~ y)
93
+ Math::unit_atan2(x.base_scalar, y.base_scalar)
94
+ else
95
+ Math::unit_atan2(x,y)
96
+ end
97
+ end
98
+ module_function :unit_atan2
99
+ module_function :atan2
100
+
101
+ end
@@ -0,0 +1,8 @@
1
+ # make a unitless unit with a given scalar
2
+ class Numeric
3
+ def to_unit(other = nil)
4
+ other ? Unit.new(self, other) : Unit.new(self)
5
+ end
6
+ alias :unit :to_unit
7
+ alias :u :to_unit
8
+ end
@@ -0,0 +1,8 @@
1
+ class Object
2
+ def Unit(*other)
3
+ other.to_unit
4
+ end
5
+
6
+ alias :U :Unit
7
+ alias :u :Unit
8
+ end
@@ -0,0 +1,122 @@
1
+ require 'time'
2
+ # make a string into a unit
3
+ class String
4
+ def to_unit(other = nil)
5
+ other ? Unit.new(self).to(other) : Unit.new(self)
6
+ end
7
+ alias :unit :to_unit
8
+ alias :u :to_unit
9
+ alias :unit_format :%
10
+
11
+ # format unit output using formating codes '%0.2f' % '1 mm'.unit => '1.00 mm'
12
+ def %(*args)
13
+ return "" if self.empty?
14
+ case
15
+ when args.first.is_a?(Unit)
16
+ args.first.to_s(self)
17
+ when (!defined?(Uncertain).nil? && args.first.is_a?(Uncertain))
18
+ args.first.to_s(self)
19
+ when args.first.is_a?(Complex)
20
+ args.first.to_s
21
+ else
22
+ unit_format(*args)
23
+ end
24
+ end
25
+
26
+ #needed for compatibility with Rails, which defines a String.from method
27
+ if self.public_instance_methods.include? 'from'
28
+ alias :old_from :from
29
+ end
30
+
31
+ # "5 min".from("now")
32
+ def from(time_point = ::Time.now)
33
+ return old_from(time_point) if self.respond_to?(:old_from) && time_point.instance_of?(Integer)
34
+ self.unit.from(time_point)
35
+ end
36
+
37
+ alias :after :from
38
+
39
+ def from_now
40
+ self.from('now')
41
+ end
42
+
43
+ # "5 min".ago
44
+ def ago
45
+ self.unit.ago
46
+ end
47
+
48
+ def before(time_point = ::Time.now)
49
+ self.unit.before(time_point)
50
+ end
51
+
52
+ def before_now
53
+ self.before('now')
54
+ end
55
+
56
+ def since(time_point = ::Time.now)
57
+ self.unit.since(time_point)
58
+ end
59
+
60
+ def until(time_point = ::Time.now)
61
+ self.unit.until(time_point)
62
+ end
63
+
64
+ def time(options = {})
65
+ self.to_time(options) rescue self.to_datetime(options)
66
+ end
67
+
68
+ def to_time(options = {})
69
+ begin
70
+ #raises exception when Chronic not defined or when it returns a nil (i.e., can't parse the input)
71
+ r = Chronic.parse(self,options)
72
+ raise(ArgumentError, 'Invalid Time String') unless r
73
+ return r
74
+ rescue
75
+ case
76
+ when self == "now"
77
+ Time.now
78
+ when Time.respond_to?(:parse)
79
+ Time.parse(self)
80
+ else
81
+ Time.local(*ParseDate.parsedate(self))
82
+ end
83
+ end
84
+ end
85
+
86
+ def to_datetime(options = {})
87
+ begin
88
+ # raises an exception if Chronic.parse = nil or if Chronic not defined
89
+ r = Chronic.parse(self,options).send(:to_datetime)
90
+ rescue Exception => e
91
+ r = case
92
+ when self.to_s == "now"
93
+ DateTime.now
94
+ else
95
+ DateTime.parse(self)
96
+ end
97
+ end
98
+ raise RuntimeError, "Invalid Time String (#{self.to_s})" if r == DateTime.new
99
+ return r
100
+ end
101
+
102
+ def to_date(options={})
103
+ begin
104
+ r = Chronic.parse(self,options).to_date
105
+ rescue
106
+ r = case
107
+ when self == "today"
108
+ Date.today
109
+ when RUBY_VERSION < "1.9"
110
+ Date.civil(*ParseDate.parsedate(self)[0..5].compact)
111
+ else
112
+ Date.parse(self)
113
+ end
114
+ end
115
+ raise RuntimeError, 'Invalid Date String' if r == Date.new
116
+ return r
117
+ end
118
+
119
+ def datetime(options = {})
120
+ self.to_datetime(options) rescue self.to_time(options)
121
+ end
122
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # Time math is handled slightly differently. The difference is considered to be an exact duration if
3
+ # the subtracted value is in hours, minutes, or seconds. It is rounded to the nearest day if the offset
4
+ # is in years, decades, or centuries. This leads to less precise values, but ones that match the
5
+ # calendar better.
6
+ class Time
7
+
8
+ class << self
9
+ alias unit_time_at at
10
+ end
11
+
12
+ # Convert a duration to a Time value by considering the duration to be the number of seconds since the
13
+ # epoch
14
+ def self.at(arg)
15
+ case arg
16
+ when Unit
17
+ unit_time_at(arg.to("s").scalar)
18
+ else
19
+ unit_time_at(arg)
20
+ end
21
+ end
22
+
23
+ def to_unit(other = nil)
24
+ other ? Unit.new(self).to(other) : Unit.new(self)
25
+ end
26
+ alias :unit :to_unit
27
+ alias :u :to_unit
28
+ alias :unit_add :+
29
+
30
+ unless Time.instance_methods.include?(:to_date)
31
+ def to_date
32
+ x=(Date.civil(1970,1,1)+((self.to_f+self.gmt_offset)/86400.0)-0.5)
33
+ Date.civil(x.year, x.month, x.day)
34
+ end
35
+ end
36
+
37
+ def +(other)
38
+ case other
39
+ when Unit
40
+ other = other.to('d').round.to('s') if ['y', 'decade', 'century'].include? other.units
41
+ begin
42
+ unit_add(other.to('s').scalar)
43
+ rescue RangeError
44
+ self.to_datetime + other
45
+ end
46
+ else
47
+ unit_add(other)
48
+ end
49
+ end
50
+
51
+ # usage: Time.in '5 min'
52
+ def self.in(duration)
53
+ Time.now + duration.to_unit
54
+ end
55
+
56
+ alias :unit_sub :-
57
+
58
+ def -(other)
59
+ case other
60
+ when Unit
61
+ other = other.to('d').round.to('s') if ['y', 'decade', 'century'].include? other.units
62
+ begin
63
+ unit_sub(other.to('s').scalar)
64
+ rescue RangeError
65
+ self.send(:to_datetime) - other
66
+ end
67
+ else
68
+ unit_sub(other)
69
+ end
70
+ end
71
+ end