alchemist 0.1.6 → 0.1.7
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.
- 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:
|