alchemist 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ ---
2
+ :yotta: 1.2089258196146292e+24
3
+ :Y: 1.2089258196146292e+24
4
+ :zetta: 1.1805916207174113e+21
5
+ :Z: 1.1805916207174113e+21
6
+ :exa: 1.152921504606847e+18
7
+ :E: 1.152921504606847e+18
8
+ :peta: 1.125899906842624e+15
9
+ :P: 1.125899906842624e+15
10
+ :tera: 1099511627776.0
11
+ :T: 1099511627776.0
12
+ :giga: 1073741824.0
13
+ :G: 1073741824.0
14
+ :mega: 1048576.0
15
+ :M: 1048576.0
16
+ :kilo: 1024.0
17
+ :k: 1024.0
18
+ :kibi: 1024.0
19
+ :Ki: 1024.0
20
+ :mebi: 1048576.0
21
+ :Mi: 1048576.0
22
+ :gibi: 1073741824.0
23
+ :Gi: 1073741824.0
24
+ :tebi: 1099511627776.0
25
+ :Ti: 1099511627776.0
26
+ :pebi: 1.125899906842624e+15
27
+ :Pi: 1.125899906842624e+15
28
+ :exbi: 1.152921504606847e+18
29
+ :Ei: 1.152921504606847e+18
30
+ :zebi: 1.1805916207174113e+21
31
+ :Zi: 1.1805916207174113e+21
32
+ :yobi: 1.2089258196146292e+24
33
+ :Yi: 1.2089258196146292e+24
@@ -0,0 +1,76 @@
1
+ ---
2
+ - m
3
+ - meter
4
+ - metre
5
+ - meters
6
+ - metres
7
+ - liter
8
+ - litre
9
+ - litres
10
+ - liters
11
+ - l
12
+ - L
13
+ - farad
14
+ - farads
15
+ - F
16
+ - coulombs
17
+ - C
18
+ - gray
19
+ - grays
20
+ - Gy
21
+ - siemen
22
+ - siemens
23
+ - S
24
+ - mhos
25
+ - mho
26
+ - ohm
27
+ - ohms
28
+ - volt
29
+ - volts
30
+ - V
31
+ - joule
32
+ - joules
33
+ - J
34
+ - newton
35
+ - newtons
36
+ - N
37
+ - lux
38
+ - lx
39
+ - henry
40
+ - henrys
41
+ - H
42
+ - b
43
+ - B
44
+ - bits
45
+ - bytes
46
+ - bit
47
+ - byte
48
+ - lumen
49
+ - lumens
50
+ - lm
51
+ - candela
52
+ - candelas
53
+ - cd
54
+ - tesla
55
+ - teslas
56
+ - T
57
+ - gauss
58
+ - Gs
59
+ - G
60
+ - gram
61
+ - gramme
62
+ - grams
63
+ - grammes
64
+ - g
65
+ - watt
66
+ - watts
67
+ - W
68
+ - pascal
69
+ - pascals
70
+ - Pa
71
+ - becquerel
72
+ - becquerels
73
+ - Bq
74
+ - curie
75
+ - curies
76
+ - Ci
@@ -0,0 +1,58 @@
1
+ ---
2
+ :googol: 1.0e+100
3
+ :yotta: 1.0e+24
4
+ :Y: 1.0e+24
5
+ :zetta: 1.0e+21
6
+ :Z: 1.0e+21
7
+ :exa: 1.0e+18
8
+ :E: 1.0e+18
9
+ :peta: 1.0e+15
10
+ :P: 1.0e+15
11
+ :tera: 1000000000000.0
12
+ :T: 1000000000000.0
13
+ :giga: 1000000000.0
14
+ :G: 1000000000.0
15
+ :mega: 1000000.0
16
+ :M: 1000000.0
17
+ :kilo: 1000.0
18
+ :k: 1000.0
19
+ :hecto: 100.0
20
+ :h: 100.0
21
+ :deca: 10
22
+ :da: 10
23
+ :deci: 0.1
24
+ :d: 0.1
25
+ :centi: 0.01
26
+ :c: 0.01
27
+ :milli: 0.001
28
+ :m: 0.001
29
+ :micro: 1.0e-06
30
+ :u: 1.0e-06
31
+ :nano: 1.0e-09
32
+ :n: 1.0e-09
33
+ :pico: 1.0e-12
34
+ :p: 1.0e-12
35
+ :femto: 1.0e-15
36
+ :f: 1.0e-15
37
+ :atto: 1.0e-18
38
+ :a: 1.0e-18
39
+ :zepto: 1.0e-21
40
+ :z: 1.0e-21
41
+ :yocto: 1.0e-24
42
+ :y: 1.0e-24
43
+ :kibi: 1024.0
44
+ :Ki: 1024.0
45
+ :mebi: 1048576.0
46
+ :Mi: 1048576.0
47
+ :gibi: 1073741824.0
48
+ :Gi: 1073741824.0
49
+ :tebi: 1099511627776.0
50
+ :Ti: 1099511627776.0
51
+ :pebi: 1.125899906842624e+15
52
+ :Pi: 1.125899906842624e+15
53
+ :exbi: 1.152921504606847e+18
54
+ :Ei: 1.152921504606847e+18
55
+ :zebi: 1.1805916207174113e+21
56
+ :Zi: 1.1805916207174113e+21
57
+ :yobi: 1.2089258196146292e+24
58
+ :Yi: 1.2089258196146292e+24
@@ -0,0 +1,9 @@
1
+ require 'alchemist'
2
+
3
+ module Alchemist
4
+ class Measurement
5
+ def geospatial
6
+ Alchemist::Earth.new(self).geospatial
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,128 @@
1
+ require "alchemist/measurement_convertor"
2
+
3
+ module Alchemist
4
+ class Measurement
5
+ include Comparable
6
+
7
+ attr_reader :unit_name, :exponent, :value
8
+
9
+ def initialize value, unit_name, exponent = 1.0
10
+ @value = value.to_f
11
+ @unit_name = unit_name
12
+ @exponent = exponent
13
+ end
14
+
15
+ def per
16
+ CompoundMeasurement.new self
17
+ end
18
+
19
+ def to type = nil
20
+ if type
21
+ convertor.send(type)
22
+ else
23
+ convertor
24
+ end
25
+ end
26
+
27
+ def + measurement
28
+ ensure_shared_type!(measurement)
29
+ converted = measurement.to(unit_name)
30
+ Measurement.new(value + converted.value, unit_name, exponent)
31
+ end
32
+
33
+ def - measurement
34
+ ensure_shared_type!(measurement)
35
+ converted = measurement.to(unit_name)
36
+ Measurement.new(value - converted.value, unit_name, exponent)
37
+ end
38
+
39
+ def / measurement
40
+ ensure_shared_type!(measurement)
41
+ dividend = measurement.is_a?(Measurement) ? measurement.to(unit_name).to_f / exponent : measurement
42
+ Measurement.new(value / dividend, unit_name, exponent).value
43
+ end
44
+
45
+ def * multiplicand
46
+ if multiplicand.is_a?(Numeric)
47
+ Measurement.new(value * multiplicand, unit_name, exponent)
48
+ else
49
+ try_raising_dimension(multiplicand)
50
+ end
51
+ end
52
+
53
+ def base unit_type
54
+ conversion_base = conversion_base_for(unit_type)
55
+ convert_to_base conversion_base
56
+ end
57
+
58
+ def to_s
59
+ value.to_s
60
+ end
61
+
62
+ def to_i
63
+ value.to_i
64
+ end
65
+
66
+ def to_f
67
+ @value
68
+ end
69
+
70
+ def <=>(other)
71
+ (self.to_f * exponent).to_f <=> other.to(unit_name).to_f
72
+ end
73
+
74
+ def types
75
+ Alchemist.measurement_for(unit_name)
76
+ end
77
+
78
+ def shared_types other_unit_name
79
+ types & Alchemist.measurement_for(other_unit_name)
80
+ end
81
+
82
+ def coerce(number)
83
+ [self, number]
84
+ end
85
+
86
+ private
87
+
88
+ def ensure_shared_type! measurement
89
+ if !has_shared_types?(measurement.unit_name)
90
+ incompatible_types
91
+ end
92
+ end
93
+
94
+ def convert_to_base conversion_base
95
+ if conversion_base.is_a?(Array)
96
+ exponent * conversion_base.first.call(value)
97
+ else
98
+ exponent * value * conversion_base
99
+ end
100
+ end
101
+
102
+ def conversion_base_for unit_type
103
+ Alchemist.conversion_table[unit_type][unit_name]
104
+ end
105
+
106
+ def has_shared_types? other_unit_name
107
+ shared_types(other_unit_name).length > 0
108
+ end
109
+
110
+ def try_raising_dimension(measurement)
111
+ valid_types = shared_types(measurement.unit_name)
112
+ Alchemist.operator_actions[:*].each do |s1, s2, new_type|
113
+ if (valid_types & [s1, s2]).any?
114
+ return Alchemist.measure(value * measurement.to_f, new_type)
115
+ end
116
+ end
117
+ incompatible_types
118
+ end
119
+
120
+ def incompatible_types
121
+ raise Exception, "Incompatible Types"
122
+ end
123
+
124
+ def convertor
125
+ MeasurementConvertor.new(self)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,35 @@
1
+ require 'bigdecimal'
2
+
3
+ module Alchemist
4
+ class MeasurementConvertor
5
+ def initialize from
6
+ @from = from
7
+ end
8
+
9
+ def method_missing method, *args, &block
10
+ exponent, unit_name = Alchemist.parse_prefix(method)
11
+ convert(from.shared_types(unit_name), unit_name, exponent)
12
+ end
13
+
14
+ private
15
+ attr_reader :from
16
+
17
+ def convert types, unit_name, exponent
18
+ if type = types[0]
19
+ conversion_base = BigDecimal.new(from.base(type).to_s)
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
26
+ else
27
+ raise Exception, "Incompatible Types"
28
+ end
29
+ end
30
+
31
+ def proc_based? conversion_factor
32
+ conversion_factor.is_a? Array
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ module Alchemist
2
+ class ModuleBuilder
3
+ def initialize category
4
+ @category = category
5
+ end
6
+
7
+ def build
8
+ Module.new.tap do |category_module|
9
+ category_module.class_eval %(def self.inspect() "#<Module(#{category})>" end)
10
+ category_module.class_eval category_methods
11
+ end
12
+ end
13
+
14
+ private
15
+ attr_reader :category
16
+
17
+ def category_methods
18
+ unit_names.map do |name|
19
+ %(define_method("#{name}") { Alchemist.measure self, :#{name} }) + "\n" + prefixed_methods(name)
20
+ end.join("\n")
21
+ end
22
+
23
+ def unit_names
24
+ Alchemist.conversion_table[category.to_sym].map { |values| values[0] }
25
+ end
26
+
27
+ def prefixes_with_value(name)
28
+ if Alchemist.si_units.include?(name.to_s)
29
+ Alchemist.unit_prefixes
30
+ else
31
+ []
32
+ end
33
+ end
34
+
35
+ def prefixed_methods(name)
36
+ prefixes_with_value(name).map do |prefix, value|
37
+ %(define_method("#{prefix}#{name}") { Alchemist.measure self, :#{name}, #{value} })
38
+ end.join("\n")
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ module Alchemist
2
+ class Earth
3
+ RADIUS = Alchemist.measure(6378100, :meters)
4
+
5
+ def initialize measurement
6
+ @measurement = measurement
7
+ end
8
+
9
+ def geospatial
10
+ if types.include?(:angles)
11
+ geospatial_angle_to_arc
12
+ elsif types.include?(:distance)
13
+ geospatial_arc_to_angle
14
+ else
15
+ raise Exception, "geospatial must either be angles or distance"
16
+ end
17
+ end
18
+
19
+ private
20
+ attr_reader :measurement, :base
21
+
22
+ def types
23
+ measurement.types
24
+ end
25
+
26
+ def geospatial_angle_to_arc
27
+ measurement.to(:radians).to_f * RADIUS
28
+ end
29
+
30
+ def geospatial_arc_to_angle
31
+ Alchemist.measure(measurement.to(:meters) / RADIUS, :radians)
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module Alchemist
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Alchemist do
4
+
5
+ it "sets up Numeric" do
6
+ category_module = double()
7
+ module_builder = double()
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)
13
+ Alchemist.setup('distance')
14
+ end
15
+
16
+ it "creates a measurement" do
17
+ unit = Alchemist.measure(1, :meter)
18
+ expect(unit).to eq(1.meter)
19
+ end
20
+
21
+ it "knows if it has a measurement" do
22
+ expect(Alchemist.has_measurement?(:meter)).to be_true
23
+ end
24
+
25
+ it "knows if it doesn't have a measurement" do
26
+ expect(Alchemist.has_measurement?(:wombat)).to be_false
27
+ end
28
+
29
+ it "can register units" do
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])
50
+ end
51
+ end