alchemist 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/alchemist.rb +3 -114
- data/lib/alchemist/compound_measurement.rb +2 -2
- data/lib/alchemist/configuration.rb +26 -0
- data/lib/alchemist/library.rb +86 -0
- data/lib/alchemist/measurement.rb +49 -16
- data/lib/alchemist/measurement_convertor.rb +25 -9
- data/lib/alchemist/module_builder.rb +3 -3
- data/lib/alchemist/prefix_parser.rb +42 -0
- data/lib/alchemist/setup.rb +3 -0
- data/lib/alchemist/version.rb +1 -1
- data/spec/alchemist_spec.rb +15 -34
- data/spec/conversion_table_spec.rb +3 -3
- data/spec/library_spec.rb +39 -0
- data/spec/measurement_spec.rb +21 -1
- data/spec/prefix_parser_spec.rb +10 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f47215664aef5b08025bbf14fcb971c7b3d8d726
|
4
|
+
data.tar.gz: 92dcc4243340af6f1e4cacfb9593f292a8fdf16c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f38ec388bac7cea190f0ace7bca99c2d5da955f4fa6ce4719cbca2cd4df603ccdfb53bc33e8125ff87169d77bb63873fe927c5e42be43b02549802cf163cd39
|
7
|
+
data.tar.gz: 085ddcae66c574428f71b8c9c2a2b149144ba80debc5585c88d82723e2bd0c0b96bd2fc71166d1920e2815adc242c989d4e49f59c852093d1bed281153ffb5e2
|
data/Gemfile.lock
CHANGED
data/lib/alchemist.rb
CHANGED
@@ -2,132 +2,21 @@ require "alchemist/conversion_table"
|
|
2
2
|
require "alchemist/measurement"
|
3
3
|
require "alchemist/compound_measurement"
|
4
4
|
require "alchemist/module_builder"
|
5
|
+
require "alchemist/configuration"
|
6
|
+
require "alchemist/library"
|
5
7
|
|
6
8
|
module Alchemist
|
7
9
|
autoload :Earth, "alchemist/objects/planets/earth"
|
8
10
|
|
9
|
-
DATA_DIR = File.join(File.dirname(__FILE__), "alchemist", "data")
|
10
|
-
|
11
|
-
DEFAULT_UNITS_FILE = File.join(DATA_DIR, "units.yml")
|
12
|
-
DEFAULT_BINARY_PREFIXES_FILE = File.join(DATA_DIR, "binary_prefixes.yml")
|
13
|
-
DEFAULT_SI_UNITS_FILE = File.join(DATA_DIR, "si_units.yml")
|
14
|
-
DEFAULT_UNIT_PREFIXES_FILE = File.join(DATA_DIR, "unit_prefixes.yml")
|
15
|
-
|
16
11
|
def self.setup category = nil
|
17
12
|
if category
|
18
13
|
Numeric.send(:include, ModuleBuilder.new(category).build)
|
19
14
|
else
|
20
|
-
|
15
|
+
library.categories.each { |category| Numeric.send(:include, ModuleBuilder.new(category).build) }
|
21
16
|
end
|
22
17
|
end
|
23
18
|
|
24
19
|
def self.measure value, unit, exponent = 1.0
|
25
20
|
Measurement.new value, unit, exponent
|
26
21
|
end
|
27
|
-
|
28
|
-
def self.has_measurement? name
|
29
|
-
conversions.keys.include? name.to_sym
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.measurement_for name
|
33
|
-
conversions[ name.to_sym ]
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.register(type, names, value)
|
37
|
-
names = Array(names)
|
38
|
-
value = value.is_a?(Measurement) ? value.base(type) : value
|
39
|
-
Alchemist.conversion_table[type] ||= {}
|
40
|
-
|
41
|
-
names.each do |name|
|
42
|
-
conversions[name] ||= []
|
43
|
-
conversions[name] << type
|
44
|
-
Alchemist.conversion_table[type][name] = value
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.parse_prefix(unit)
|
49
|
-
matches = unit.to_s.match(prefix_matcher)
|
50
|
-
prefix, parsed_unit = matches.captures
|
51
|
-
|
52
|
-
if prefix && si_units.include?(parsed_unit)
|
53
|
-
value = prefixed_value_for(prefix.to_sym, parsed_unit)
|
54
|
-
[value, parsed_unit.to_sym]
|
55
|
-
else
|
56
|
-
[1, unit]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.register_operation_conversions type, other_type, operation, converted_type
|
61
|
-
operator_actions[operation] ||= []
|
62
|
-
operator_actions[operation] << [type, other_type, converted_type]
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.operator_actions
|
66
|
-
@operator_actions ||= {}
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.binary_prefixes
|
70
|
-
@binary_prefixes ||= YAML.load_file(DEFAULT_BINARY_PREFIXES_FILE)
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.si_units
|
74
|
-
@si_units ||= YAML.load_file(DEFAULT_SI_UNITS_FILE)
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.unit_prefixes
|
78
|
-
@unit_prefixes ||= YAML.load_file(DEFAULT_UNIT_PREFIXES_FILE)
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.use_si
|
82
|
-
@use_si ||= false
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.use_si= use_si
|
86
|
-
@use_si = use_si
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.load_conversion_table(filename=DEFAULT_UNITS_FILE)
|
90
|
-
@conversion_table = ConversionTable.new.load_all(filename)
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.conversion_table
|
94
|
-
@conversion_table ||= load_conversion_table
|
95
|
-
end
|
96
|
-
|
97
|
-
def self.conversions
|
98
|
-
@conversions ||= load_conversions
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
|
-
private
|
103
|
-
|
104
|
-
def self.use_binary_prefix? unit
|
105
|
-
!use_si && measurement_for(unit).include?(:information_storage)
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.prefix_matcher
|
109
|
-
@prefix_matcher ||= begin
|
110
|
-
prefix_keys = unit_prefixes.keys.map(&:to_s).sort{ |a,b| b.length <=> a.length }
|
111
|
-
%r{^(#{prefix_keys.join('|')})?(.+)}
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def self.prefixed_value_for prefix, unit
|
116
|
-
if use_binary_prefix? unit
|
117
|
-
binary_prefixes[prefix]
|
118
|
-
else
|
119
|
-
unit_prefixes[prefix]
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def self.load_conversions
|
124
|
-
conversions = {}
|
125
|
-
conversion_table.each do |type, table_conversions|
|
126
|
-
table_conversions.each do |name, value|
|
127
|
-
conversions[name] ||= []
|
128
|
-
conversions[name] << type
|
129
|
-
end
|
130
|
-
end
|
131
|
-
conversions
|
132
|
-
end
|
133
22
|
end
|
@@ -42,7 +42,7 @@ module Alchemist
|
|
42
42
|
|
43
43
|
def should_remove_units? numerator, denominator
|
44
44
|
return false if numerator.is_a?(Numeric) || denominator.is_a?(Numeric)
|
45
|
-
(Alchemist.measurement_for(numerator.unit_name) & Alchemist.measurement_for(denominator.unit_name)).length > 0
|
45
|
+
(Alchemist.library.measurement_for(numerator.unit_name) & Alchemist.library.measurement_for(denominator.unit_name)).length > 0
|
46
46
|
end
|
47
47
|
|
48
48
|
def set_coefficients
|
@@ -56,7 +56,7 @@ module Alchemist
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def method_missing(method, *attrs, &block)
|
59
|
-
if Alchemist.measurement_for(method)
|
59
|
+
if Alchemist.library.measurement_for(method)
|
60
60
|
@denominators << Alchemist.measure(1, method)
|
61
61
|
consolidate
|
62
62
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Alchemist
|
4
|
+
def self.config
|
5
|
+
Configuration.instance
|
6
|
+
end
|
7
|
+
|
8
|
+
class Configuration
|
9
|
+
DATA_DIR = File.join(File.dirname(__FILE__), "data")
|
10
|
+
DEFAULT_UNITS_FILE = File.join(DATA_DIR, "units.yml")
|
11
|
+
DEFAULT_SI_UNITS_FILE = File.join(DATA_DIR, "si_units.yml")
|
12
|
+
DEFAULT_BINARY_PREFIXES_FILE = File.join(DATA_DIR, "binary_prefixes.yml")
|
13
|
+
DEFAULT_UNIT_PREFIXES_FILE = File.join(DATA_DIR, "unit_prefixes.yml")
|
14
|
+
|
15
|
+
include Singleton
|
16
|
+
|
17
|
+
attr_accessor :use_si
|
18
|
+
def initialize
|
19
|
+
@use_si = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def use_si?
|
23
|
+
@use_si
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Alchemist
|
4
|
+
def self.library
|
5
|
+
Library.instance
|
6
|
+
end
|
7
|
+
|
8
|
+
class Library
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
attr_reader :si_units, :unit_prefixes, :conversion_table, :binary_prefixes
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@conversion_table = load_conversion_table
|
15
|
+
@si_units = YAML.load_file(Configuration::DEFAULT_SI_UNITS_FILE)
|
16
|
+
@unit_prefixes = YAML.load_file(Configuration::DEFAULT_UNIT_PREFIXES_FILE)
|
17
|
+
@binary_prefixes = YAML.load_file(Configuration::DEFAULT_BINARY_PREFIXES_FILE)
|
18
|
+
end
|
19
|
+
|
20
|
+
def categories
|
21
|
+
@conversion_table.keys
|
22
|
+
end
|
23
|
+
|
24
|
+
def unit_names category
|
25
|
+
@conversion_table[category.to_sym].map { |values| values[0] }
|
26
|
+
end
|
27
|
+
|
28
|
+
def measurement_for unit_name
|
29
|
+
conversions[ unit_name.to_sym ]
|
30
|
+
end
|
31
|
+
|
32
|
+
def conversions
|
33
|
+
@conversions ||= load_conversions
|
34
|
+
end
|
35
|
+
|
36
|
+
def conversion_base_for(unit_type, unit_name)
|
37
|
+
@conversion_table[unit_type][unit_name]
|
38
|
+
end
|
39
|
+
|
40
|
+
def has_measurement? name
|
41
|
+
conversions.keys.include? name.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
def register_operation_conversions type, other_type, operation, converted_type
|
45
|
+
operator_actions[operation] ||= []
|
46
|
+
operator_actions[operation] << [type, other_type, converted_type]
|
47
|
+
end
|
48
|
+
|
49
|
+
def operator_actions
|
50
|
+
@operator_actions ||= {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_conversion_table(filename=Configuration::DEFAULT_UNITS_FILE)
|
54
|
+
if new_table = ConversionTable.new.load_all(filename)
|
55
|
+
@conversion_table = new_table
|
56
|
+
else
|
57
|
+
@conversion_table ||= load_conversion_table
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def register(type, names, value)
|
62
|
+
names = Array(names)
|
63
|
+
value = value.is_a?(Measurement) ? value.base(type) : value
|
64
|
+
conversion_table[type] ||= {}
|
65
|
+
|
66
|
+
names.each do |name|
|
67
|
+
conversions[name] ||= []
|
68
|
+
conversions[name] << type
|
69
|
+
conversion_table[type][name] = value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def load_conversions
|
76
|
+
conversions = {}
|
77
|
+
conversion_table.each do |type, table_conversions|
|
78
|
+
table_conversions.each do |name, value|
|
79
|
+
conversions[name] ||= []
|
80
|
+
conversions[name] << type
|
81
|
+
end
|
82
|
+
end
|
83
|
+
conversions
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -18,7 +18,7 @@ module Alchemist
|
|
18
18
|
|
19
19
|
def to type = nil
|
20
20
|
if type
|
21
|
-
convertor.send(type)
|
21
|
+
convertor.send(type, exponent)
|
22
22
|
else
|
23
23
|
convertor
|
24
24
|
end
|
@@ -27,24 +27,28 @@ module Alchemist
|
|
27
27
|
def + measurement
|
28
28
|
ensure_shared_type!(measurement)
|
29
29
|
converted = measurement.to(unit_name)
|
30
|
-
|
30
|
+
remeasure(value + converted.value)
|
31
31
|
end
|
32
32
|
|
33
33
|
def - measurement
|
34
34
|
ensure_shared_type!(measurement)
|
35
35
|
converted = measurement.to(unit_name)
|
36
|
-
|
36
|
+
remeasure(value - converted.value)
|
37
37
|
end
|
38
38
|
|
39
39
|
def / measurement
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
converted = remeasure(value / dividend(measurement))
|
41
|
+
|
42
|
+
if measurement.is_a?(Measurement)
|
43
|
+
converted.value
|
44
|
+
else
|
45
|
+
converted
|
46
|
+
end
|
43
47
|
end
|
44
48
|
|
45
49
|
def * multiplicand
|
46
50
|
if multiplicand.is_a?(Numeric)
|
47
|
-
|
51
|
+
remeasure(value * multiplicand)
|
48
52
|
else
|
49
53
|
try_raising_dimension(multiplicand)
|
50
54
|
end
|
@@ -52,39 +56,68 @@ module Alchemist
|
|
52
56
|
|
53
57
|
def base unit_type
|
54
58
|
conversion_base = conversion_base_for(unit_type)
|
55
|
-
convert_to_base
|
59
|
+
convert_to_base(conversion_base)
|
56
60
|
end
|
57
61
|
|
58
62
|
def to_s
|
59
|
-
|
63
|
+
to_f.to_s
|
60
64
|
end
|
61
65
|
|
62
66
|
def to_i
|
63
|
-
|
67
|
+
to_f.to_i
|
64
68
|
end
|
65
69
|
|
66
70
|
def to_f
|
67
|
-
@value
|
71
|
+
@value * exponent
|
68
72
|
end
|
69
73
|
|
70
74
|
def <=>(other)
|
71
|
-
|
75
|
+
self.to_f <=> other.to(unit_name).to_f
|
72
76
|
end
|
73
77
|
|
74
78
|
def types
|
75
|
-
|
79
|
+
library.measurement_for(unit_name)
|
76
80
|
end
|
77
81
|
|
78
82
|
def shared_types other_unit_name
|
79
|
-
types &
|
83
|
+
types & library.measurement_for(other_unit_name)
|
80
84
|
end
|
81
85
|
|
82
86
|
def coerce(number)
|
83
87
|
[self, number]
|
84
88
|
end
|
85
89
|
|
90
|
+
def round(*args)
|
91
|
+
remeasure(value.round(*args))
|
92
|
+
end
|
93
|
+
|
94
|
+
def ceil(*args)
|
95
|
+
remeasure(value.ceil(*args))
|
96
|
+
end
|
97
|
+
|
98
|
+
def floor(*args)
|
99
|
+
remeasure(value.floor(*args))
|
100
|
+
end
|
101
|
+
|
86
102
|
private
|
87
103
|
|
104
|
+
def dividend measurement
|
105
|
+
if measurement.is_a?(Measurement)
|
106
|
+
ensure_shared_type!(measurement)
|
107
|
+
measurement.to(unit_name).to_f / exponent
|
108
|
+
else
|
109
|
+
measurement
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def remeasure value
|
114
|
+
Measurement.new(value, unit_name, exponent)
|
115
|
+
end
|
116
|
+
|
117
|
+
def library
|
118
|
+
Library.instance
|
119
|
+
end
|
120
|
+
|
88
121
|
def ensure_shared_type! measurement
|
89
122
|
if !has_shared_types?(measurement.unit_name)
|
90
123
|
incompatible_types
|
@@ -100,7 +133,7 @@ module Alchemist
|
|
100
133
|
end
|
101
134
|
|
102
135
|
def conversion_base_for unit_type
|
103
|
-
|
136
|
+
library.conversion_base_for(unit_type, unit_name)
|
104
137
|
end
|
105
138
|
|
106
139
|
def has_shared_types? other_unit_name
|
@@ -109,7 +142,7 @@ module Alchemist
|
|
109
142
|
|
110
143
|
def try_raising_dimension(measurement)
|
111
144
|
valid_types = shared_types(measurement.unit_name)
|
112
|
-
|
145
|
+
library.operator_actions[:*].each do |s1, s2, new_type|
|
113
146
|
if (valid_types & [s1, s2]).any?
|
114
147
|
return Alchemist.measure(value * measurement.to_f, new_type)
|
115
148
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'bigdecimal'
|
2
|
+
require 'alchemist/prefix_parser'
|
2
3
|
|
3
4
|
module Alchemist
|
4
5
|
class MeasurementConvertor
|
@@ -7,27 +8,42 @@ module Alchemist
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def method_missing method, *args, &block
|
10
|
-
exponent, unit_name =
|
11
|
-
convert(from.shared_types(unit_name), unit_name, exponent)
|
11
|
+
exponent, unit_name = PrefixParser.new.parse(method)
|
12
|
+
convert(from.shared_types(unit_name), unit_name, args.first || exponent)
|
12
13
|
end
|
13
14
|
|
14
15
|
private
|
15
16
|
attr_reader :from
|
16
17
|
|
18
|
+
def library
|
19
|
+
Library.instance
|
20
|
+
end
|
21
|
+
|
17
22
|
def convert types, unit_name, exponent
|
18
23
|
if type = types[0]
|
19
|
-
|
20
|
-
conversion_factor = Alchemist.conversion_table[type][unit_name]
|
21
|
-
if proc_based?(conversion_factor)
|
22
|
-
Measurement.new(conversion_factor[1].call(conversion_base), unit_name, exponent)
|
23
|
-
else
|
24
|
-
Measurement.new(conversion_base / BigDecimal.new(conversion_factor.to_s), unit_name, exponent)
|
25
|
-
end
|
24
|
+
convert_from_type(type, unit_name, exponent)
|
26
25
|
else
|
27
26
|
raise Exception, "Incompatible Types"
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
30
|
+
def convert_from_type(type, unit_name, exponent)
|
31
|
+
conversion_base = BigDecimal.new(from.base(type).to_s)
|
32
|
+
conversion_factor = library.conversion_base_for(type, unit_name)
|
33
|
+
|
34
|
+
value = value_from(conversion_base, conversion_factor)
|
35
|
+
Measurement.new(value / exponent, unit_name, exponent)
|
36
|
+
end
|
37
|
+
|
38
|
+
def value_from(base, factor)
|
39
|
+
if proc_based?(factor)
|
40
|
+
factor[1].call(base)
|
41
|
+
else
|
42
|
+
base / BigDecimal.new(factor.to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
31
47
|
def proc_based? conversion_factor
|
32
48
|
conversion_factor.is_a? Array
|
33
49
|
end
|
@@ -21,12 +21,12 @@ module Alchemist
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def unit_names
|
24
|
-
|
24
|
+
Library.instance.unit_names(category)
|
25
25
|
end
|
26
26
|
|
27
27
|
def prefixes_with_value(name)
|
28
|
-
if
|
29
|
-
|
28
|
+
if Library.instance.si_units.include?(name.to_s)
|
29
|
+
Library.instance.unit_prefixes
|
30
30
|
else
|
31
31
|
[]
|
32
32
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Alchemist
|
2
|
+
class PrefixParser
|
3
|
+
def parse(unit)
|
4
|
+
matches = unit.to_s.match(prefix_matcher)
|
5
|
+
prefix, parsed_unit = matches.captures
|
6
|
+
|
7
|
+
if prefix && library.si_units.include?(parsed_unit)
|
8
|
+
value = prefixed_value_for(prefix.to_sym, parsed_unit)
|
9
|
+
[value, parsed_unit.to_sym]
|
10
|
+
else
|
11
|
+
[1, unit]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def prefix_matcher
|
16
|
+
@prefix_matcher ||= generate_prefix_matcher
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def library
|
22
|
+
Alchemist.library
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_prefix_matcher
|
26
|
+
prefix_keys = library.unit_prefixes.keys.map(&:to_s).sort{ |a,b| b.length <=> a.length }
|
27
|
+
%r{^(#{prefix_keys.join('|')})?(.+)}
|
28
|
+
end
|
29
|
+
|
30
|
+
def prefixed_value_for prefix, unit
|
31
|
+
if use_binary_prefix? unit
|
32
|
+
library.binary_prefixes[prefix]
|
33
|
+
else
|
34
|
+
library.unit_prefixes[prefix]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def use_binary_prefix? unit
|
39
|
+
!Alchemist.config.use_si? && library.measurement_for(unit).include?(:information_storage)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/alchemist/version.rb
CHANGED
data/spec/alchemist_spec.rb
CHANGED
@@ -3,14 +3,11 @@ require 'spec_helper'
|
|
3
3
|
describe Alchemist do
|
4
4
|
|
5
5
|
it "sets up Numeric" do
|
6
|
-
category_module =
|
7
|
-
|
8
|
-
module_builder.should_receive(:build).and_return(category_module)
|
9
|
-
fake_module = double()
|
10
|
-
fake_module.should_receive(:include).with(category_module)
|
11
|
-
Alchemist::ModuleBuilder.should_receive(:new).with('distance').and_return(module_builder)
|
12
|
-
stub_const("Numeric", fake_module)
|
6
|
+
category_module = build_category_module
|
7
|
+
fake_numeric = build_fake_numeric
|
13
8
|
Alchemist.setup('distance')
|
9
|
+
expect(Alchemist::ModuleBuilder).to have_received(:new).with('distance')
|
10
|
+
expect(fake_numeric).to have_received(:include).with(category_module)
|
14
11
|
end
|
15
12
|
|
16
13
|
it "creates a measurement" do
|
@@ -18,34 +15,18 @@ describe Alchemist do
|
|
18
15
|
expect(unit).to eq(1.meter)
|
19
16
|
end
|
20
17
|
|
21
|
-
|
22
|
-
|
18
|
+
def build_category_module
|
19
|
+
double.tap do |category_module|
|
20
|
+
module_builder = double()
|
21
|
+
allow(module_builder).to receive(:build) { category_module }
|
22
|
+
Alchemist::ModuleBuilder.stub(:new).and_return(module_builder)
|
23
|
+
end
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
Alchemist.register :quux, :qaat, 1.0
|
31
|
-
Alchemist.register :quux, :quut, 3.0
|
32
|
-
expect(Alchemist.conversion_table[:quux]).to eq({:qaat=>1.0, :quut=>3.0})
|
33
|
-
end
|
34
|
-
|
35
|
-
it "can register units with plural names" do
|
36
|
-
Alchemist.register(:beards, [:beard_second, :beard_seconds], 1.0)
|
37
|
-
expect(Alchemist.conversion_table[:beards]).to eq({:beard_second=>1.0, :beard_seconds=>1.0})
|
38
|
-
end
|
39
|
-
|
40
|
-
it "can register units with formulas" do
|
41
|
-
to = lambda { |t| t + 1 }
|
42
|
-
from = lambda { |t| t - 1 }
|
43
|
-
Alchemist.register(:yetis, :yeti, [to, from])
|
44
|
-
expect(Alchemist.conversion_table[:yetis]).to eq({:yeti => [to, from]})
|
45
|
-
end
|
46
|
-
|
47
|
-
it "can parse a prefix" do
|
48
|
-
parsed = Alchemist.parse_prefix(:kilometer)
|
49
|
-
expect(parsed).to eq([1000.0, :meter])
|
26
|
+
def build_fake_numeric
|
27
|
+
double.tap do |fake_module|
|
28
|
+
allow(fake_module).to receive(:include)
|
29
|
+
stub_const("Numeric", fake_module)
|
30
|
+
end
|
50
31
|
end
|
51
32
|
end
|
@@ -17,11 +17,11 @@ module Alchemist
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def conversion_table
|
20
|
-
Alchemist
|
20
|
+
Alchemist.library.conversion_table
|
21
21
|
end
|
22
22
|
|
23
23
|
def load_file file
|
24
|
-
Alchemist
|
24
|
+
Alchemist.library.load_conversion_table file
|
25
25
|
end
|
26
26
|
|
27
27
|
def good_file
|
@@ -33,7 +33,7 @@ module Alchemist
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def default_file
|
36
|
-
|
36
|
+
Configuration::DEFAULT_UNITS_FILE
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Alchemist
|
4
|
+
describe Library do
|
5
|
+
it "returns a list of the binary prefixes" do
|
6
|
+
expect(library.binary_prefixes[:kilo]).to eq(1024.0)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "can register units with formulas" do
|
10
|
+
to = lambda { |t| t + 1 }
|
11
|
+
from = lambda { |t| t - 1 }
|
12
|
+
library.register(:yetis, :yeti, [to, from])
|
13
|
+
expect(library.conversion_table[:yetis]).to eq({:yeti => [to, from]})
|
14
|
+
end
|
15
|
+
|
16
|
+
it "can register units with plural names" do
|
17
|
+
library.register(:beards, [:beard_second, :beard_seconds], 1.0)
|
18
|
+
expect(library.conversion_table[:beards]).to eq({:beard_second=>1.0, :beard_seconds=>1.0})
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can register units" do
|
22
|
+
library.register :quux, :qaat, 1.0
|
23
|
+
library.register :quux, :quut, 3.0
|
24
|
+
expect(library.conversion_table[:quux]).to eq({:qaat=>1.0, :quut=>3.0})
|
25
|
+
end
|
26
|
+
|
27
|
+
it "knows if it has a measurement" do
|
28
|
+
expect(library.has_measurement?(:meter)).to be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "knows if it doesn't have a measurement" do
|
32
|
+
expect(library.has_measurement?(:wombat)).to be_false
|
33
|
+
end
|
34
|
+
|
35
|
+
def library
|
36
|
+
Library.instance
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/measurement_spec.rb
CHANGED
@@ -15,12 +15,13 @@ module Alchemist
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "can be multiplied" do
|
18
|
-
Alchemist.register_operation_conversions(:distance, :distance, :*, :square_meters)
|
18
|
+
Alchemist.library.register_operation_conversions(:distance, :distance, :*, :square_meters)
|
19
19
|
expect(1.meter * 1.meter).to eq(1.square_meter)
|
20
20
|
end
|
21
21
|
|
22
22
|
it "can be divided" do
|
23
23
|
expect(2.meters / 1.meter).to eq(2.0)
|
24
|
+
expect(4.meters / 2).to eq(2.meters)
|
24
25
|
end
|
25
26
|
|
26
27
|
it "can be added" do
|
@@ -55,6 +56,25 @@ module Alchemist
|
|
55
56
|
expect(1.meter.coerce(10)).to eq([1.meter, 10])
|
56
57
|
end
|
57
58
|
|
59
|
+
it "can round measurements" do
|
60
|
+
expect(1.5.meters.round).to eq(2.meters)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "can ceil measurements" do
|
64
|
+
expect(1.4.meters.ceil).to eq(2.meters)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can floor measurments" do
|
68
|
+
expect(1.6.meters.floor).to eq(1.meter)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "handles exponents correctly" do
|
72
|
+
expect(1.kg.to.kg).to eq(1.kg)
|
73
|
+
expect(1.kg.to(:kg)).to eq(1.kg)
|
74
|
+
expect(1.kg.to.kg.to.g).to eq(1000.g)
|
75
|
+
expect(1.kg.to.g.to.kg).to eq(1.kg)
|
76
|
+
end
|
77
|
+
|
58
78
|
describe '#geospatial' do
|
59
79
|
|
60
80
|
it 'should convert angles to meters' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alchemist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Mongeau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -53,23 +53,29 @@ files:
|
|
53
53
|
- alchemist.gemspec
|
54
54
|
- lib/alchemist.rb
|
55
55
|
- lib/alchemist/compound_measurement.rb
|
56
|
+
- lib/alchemist/configuration.rb
|
56
57
|
- lib/alchemist/conversion_table.rb
|
57
58
|
- lib/alchemist/data/binary_prefixes.yml
|
58
59
|
- lib/alchemist/data/si_units.yml
|
59
60
|
- lib/alchemist/data/unit_prefixes.yml
|
60
61
|
- lib/alchemist/data/units.yml
|
61
62
|
- lib/alchemist/geospatial.rb
|
63
|
+
- lib/alchemist/library.rb
|
62
64
|
- lib/alchemist/measurement.rb
|
63
65
|
- lib/alchemist/measurement_convertor.rb
|
64
66
|
- lib/alchemist/module_builder.rb
|
65
67
|
- lib/alchemist/objects/planets/earth.rb
|
68
|
+
- lib/alchemist/prefix_parser.rb
|
69
|
+
- lib/alchemist/setup.rb
|
66
70
|
- lib/alchemist/version.rb
|
67
71
|
- spec/alchemist_spec.rb
|
68
72
|
- spec/compound_measurement_spec.rb
|
69
73
|
- spec/conversion_table_spec.rb
|
70
74
|
- spec/fixtures/bad_test.yml
|
71
75
|
- spec/fixtures/good_test.yml
|
76
|
+
- spec/library_spec.rb
|
72
77
|
- spec/measurement_spec.rb
|
78
|
+
- spec/prefix_parser_spec.rb
|
73
79
|
- spec/spec_helper.rb
|
74
80
|
homepage: http://github.com/halogenandtoast/alchemist
|
75
81
|
licenses:
|
@@ -101,6 +107,8 @@ test_files:
|
|
101
107
|
- spec/conversion_table_spec.rb
|
102
108
|
- spec/fixtures/bad_test.yml
|
103
109
|
- spec/fixtures/good_test.yml
|
110
|
+
- spec/library_spec.rb
|
104
111
|
- spec/measurement_spec.rb
|
112
|
+
- spec/prefix_parser_spec.rb
|
105
113
|
- spec/spec_helper.rb
|
106
114
|
has_rdoc:
|