rails-units 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +212 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +20 -0
- data/Manifest.txt +19 -0
- data/README.md +161 -0
- data/RakeFile +83 -0
- data/TODO +2 -0
- data/VERSION +1 -0
- data/lib/ruby-units.rb +14 -0
- data/lib/ruby_units.rb +14 -0
- data/lib/ruby_units/array.rb +9 -0
- data/lib/ruby_units/cache.rb +20 -0
- data/lib/ruby_units/date.rb +53 -0
- data/lib/ruby_units/fixnum.rb +20 -0
- data/lib/ruby_units/math.rb +101 -0
- data/lib/ruby_units/numeric.rb +8 -0
- data/lib/ruby_units/object.rb +8 -0
- data/lib/ruby_units/string.rb +122 -0
- data/lib/ruby_units/time.rb +71 -0
- data/lib/ruby_units/unit.rb +1272 -0
- data/lib/ruby_units/unit_definitions.rb +248 -0
- data/lib/ruby_units/version.rb +5 -0
- data/rails-units.gemspec +83 -0
- data/spec/ruby-units/array_spec.rb +14 -0
- data/spec/ruby-units/complex_spec.rb +37 -0
- data/spec/ruby-units/date_spec.rb +38 -0
- data/spec/ruby-units/math_spec.rb +63 -0
- data/spec/ruby-units/numeric_spec.rb +12 -0
- data/spec/ruby-units/object_spec.rb +7 -0
- data/spec/ruby-units/string_spec.rb +61 -0
- data/spec/ruby-units/time_spec.rb +28 -0
- data/spec/ruby-units/unit_spec.rb +888 -0
- data/spec/spec_helper.rb +4 -0
- data/test/test_cache.rb +26 -0
- data/test/test_ruby-units.rb +1011 -0
- metadata +129 -0
data/TODO
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.3.1
|
data/lib/ruby-units.rb
ADDED
@@ -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
|
+
|
data/lib/ruby_units.rb
ADDED
@@ -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,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,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
|