m9t 0.3.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.travis.yml +13 -0
- data/Gemfile +2 -2
- data/README.md +28 -23
- data/Rakefile +6 -28
- data/lib/m9t.rb +5 -21
- data/lib/m9t/base.rb +86 -43
- data/lib/m9t/direction.rb +15 -23
- data/lib/m9t/distance.rb +9 -12
- data/lib/m9t/errors.rb +9 -0
- data/lib/m9t/i18n.rb +19 -11
- data/lib/m9t/pressure.rb +7 -13
- data/lib/m9t/speed.rb +12 -15
- data/lib/m9t/temperature.rb +13 -19
- data/lib/m9t/version.rb +4 -7
- data/locales/de.yml +68 -0
- data/locales/en.yml +13 -0
- data/m9t.gemspec +19 -17
- data/spec/base_spec.rb +79 -0
- data/spec/direction_spec.rb +195 -0
- data/spec/distance_spec.rb +127 -0
- data/spec/i18n_spec.rb +54 -0
- data/spec/pressure_spec.rb +22 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/speed_spec.rb +102 -0
- data/spec/temperature_spec.rb +124 -0
- metadata +67 -47
- data/test/base_test.rb +0 -55
- data/test/direction_test.rb +0 -106
- data/test/distance_test.rb +0 -161
- data/test/i18n_test.rb +0 -30
- data/test/pressure_test.rb +0 -25
- data/test/speed_test.rb +0 -104
- data/test/temperature_test.rb +0 -111
- data/test/test_helper.rb +0 -17
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1e9e5be154c21f5d10e86c7c6f906f5bdd2287c56797965f8430c12fbcee09b2
|
4
|
+
data.tar.gz: c23bd6fe57b417fc46680c9c91dfe7517ea0833e1ec76f6cd959df5466a02028
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 12f3a7e3428384abfa69f90c2d7210dff7ba94494ae82e14b0be892159de160722ad60fd16502e68b699e228a1206af122246ff3c2062c24e14d942d0e90831f
|
7
|
+
data.tar.gz: 0b2fd9ec442f4dcaf8d992a3d301404d91c4ce6da76972affe6c40deb152f034cc6cc76a752ad921a7328748d3e4b05a40ee50edfe7675e687856fc5dcac58f1
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gemspec :
|
3
|
+
gemspec name: "m9t"
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
[![Build Status](https://secure.travis-ci.org/joeyates/m9t.png)][Continuous Integration]
|
2
|
+
[![Source Analysis](https://codeclimate.com/github/joeyates/m9t/badges/gpa.svg)](https://codeclimate.com/github/joeyates/m9t)
|
3
|
+
[![Test Coverage](https://codeclimate.com/github/joeyates/m9t/badges/coverage.svg)](https://codeclimate.com/github/joeyates/m9t/coverage)
|
4
|
+
|
5
|
+
# m9t
|
3
6
|
|
4
7
|
*Measurements and coversions library for Ruby*
|
5
8
|
|
@@ -42,45 +45,41 @@ Interface
|
|
42
45
|
|
43
46
|
new: accepts the S.I. unit as a parameter:
|
44
47
|
|
45
|
-
|
48
|
+
```ruby
|
49
|
+
height = M9t::Distance.new(1.75)
|
50
|
+
```
|
46
51
|
|
47
52
|
to_f: returns the decimal value(s):
|
48
53
|
|
49
|
-
|
54
|
+
```ruby
|
55
|
+
height.to_f -> 1.75
|
56
|
+
```
|
50
57
|
|
51
58
|
other units:
|
52
59
|
there are class methods named after each known unit,
|
53
60
|
which take values in that unit
|
54
61
|
(actually, they are defined as needed):
|
55
62
|
|
56
|
-
|
57
|
-
|
63
|
+
```ruby
|
64
|
+
marathon = M9t::Distance.miles(26.21875)
|
65
|
+
marathon.to_f -> 42194.988
|
66
|
+
```
|
58
67
|
|
59
68
|
to_s: returns a localized string with units:
|
60
69
|
|
61
|
-
|
62
|
-
|
70
|
+
```ruby
|
71
|
+
I18n.locale = :it
|
72
|
+
puts M9t::Distance.new(3).to_s -> '3 metri'
|
73
|
+
```
|
63
74
|
|
64
75
|
Class methods for conversion
|
65
76
|
============================
|
66
77
|
|
67
78
|
Methods are available for conversion between any pair of units:
|
68
79
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
=======
|
73
|
-
|
74
|
-
Coverage
|
75
|
-
--------
|
76
|
-
|
77
|
-
ruby 1.8.x:
|
78
|
-
|
79
|
-
$ rake rcov
|
80
|
-
|
81
|
-
ruby 1.9.x:
|
82
|
-
|
83
|
-
$ COVERAGE=1 rake test
|
80
|
+
```ruby
|
81
|
+
M9t::Distance.miles_to_meters(26.21875) -> 42194.988
|
82
|
+
```
|
84
83
|
|
85
84
|
Alternatives
|
86
85
|
============
|
@@ -91,6 +90,12 @@ Alternatives
|
|
91
90
|
- Monkey patches a lot of core classes:
|
92
91
|
- Adds methods to e.g. Object.
|
93
92
|
|
93
|
+
Contributors
|
94
|
+
============
|
95
|
+
|
96
|
+
* [Joe Yates](https://github.com/joeyates)
|
97
|
+
* [Florian Egermann and Mathias Wollin](https://github.com/math)
|
98
|
+
|
94
99
|
License
|
95
100
|
=======
|
96
101
|
|
data/Rakefile
CHANGED
@@ -1,32 +1,10 @@
|
|
1
|
-
|
2
|
-
require 'rake/testtask'
|
1
|
+
#!/usr/bin/env rake
|
3
2
|
|
4
|
-
|
5
|
-
require
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
6
5
|
|
7
|
-
task :
|
6
|
+
task default: :spec
|
8
7
|
|
9
|
-
|
10
|
-
t.
|
11
|
-
t.test_files = FileList['test/*_test.rb']
|
12
|
-
t.verbose = true
|
8
|
+
RSpec::Core::RakeTask.new do |t|
|
9
|
+
t.pattern = "spec/**/*_spec.rb"
|
13
10
|
end
|
14
|
-
|
15
|
-
if RUBY_VERSION < '1.9'
|
16
|
-
require 'rcov/rcovtask'
|
17
|
-
Rcov::RcovTask.new do |t|
|
18
|
-
t.test_files = FileList['test/*_test.rb']
|
19
|
-
t.rcov_opts << '--exclude /gems/'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
desc "Build the gem"
|
24
|
-
task :build do
|
25
|
-
`gem build m9t.gemspec`
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "Publish a new version of the gem"
|
29
|
-
task :release => :build do
|
30
|
-
`gem push m9t-#{M9t::VERSION::STRING}.gem`
|
31
|
-
end
|
32
|
-
|
data/lib/m9t.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2010 Joe Yates
|
2
|
+
# Copyright (c) 2010-2021 Joe Yates
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -22,26 +22,10 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
# encoding: utf-8
|
25
|
-
require 'i18n'
|
26
25
|
|
27
|
-
|
28
|
-
I18n.load_path += Dir.glob("#{ locales_path }/*.yml")
|
29
|
-
I18n.reload!
|
26
|
+
module M9t; end
|
30
27
|
|
31
|
-
libs = %w( base direction distance
|
32
|
-
libs.each do |
|
33
|
-
require "m9t/#{
|
28
|
+
libs = %w(i18n base direction distance pressure speed temperature version)
|
29
|
+
libs.each do |library|
|
30
|
+
require "m9t/#{library}"
|
34
31
|
end
|
35
|
-
|
36
|
-
module M9t
|
37
|
-
|
38
|
-
# Base class for all M9t exceptions
|
39
|
-
class M9tError < StandardError
|
40
|
-
end
|
41
|
-
|
42
|
-
# Raised when a M9t class receives an unrecogized ':units' value
|
43
|
-
class UnitError < M9tError
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
data/lib/m9t/base.rb
CHANGED
@@ -1,45 +1,65 @@
|
|
1
|
-
|
2
|
-
require
|
1
|
+
require "m9t/errors"
|
2
|
+
require "m9t/i18n"
|
3
3
|
|
4
4
|
module M9t
|
5
|
-
|
6
5
|
module Base
|
7
|
-
|
8
6
|
def self.generate_conversions(klass)
|
9
|
-
klass.instance_eval do
|
7
|
+
klass.instance_eval do
|
10
8
|
def convert(from, to, value)
|
11
9
|
value / self::CONVERSIONS[from] * self::CONVERSIONS[to]
|
12
10
|
end
|
13
11
|
|
12
|
+
# Define class conversion methods as required
|
14
13
|
def method_missing(name, *args, &block)
|
15
|
-
|
16
|
-
if
|
17
|
-
|
14
|
+
from, to = extract_from_and_to(name)
|
15
|
+
if from
|
16
|
+
if legal_conversion?(from, to)
|
17
|
+
define_conversion(from, to)
|
18
|
+
return send(name, args[0])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
if legal_constructor?(name)
|
22
|
+
define_constructor(name)
|
23
|
+
return send(name, args[0])
|
18
24
|
end
|
19
|
-
|
20
|
-
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def respond_to?(name, _include_all = false)
|
29
|
+
from, to = extract_from_and_to(name)
|
30
|
+
return true if from && legal_conversion?(from, to)
|
31
|
+
legal_constructor?(name)
|
21
32
|
end
|
22
33
|
|
23
34
|
private
|
24
35
|
|
36
|
+
def extract_from_and_to(name)
|
37
|
+
name.to_s.scan(/^(\w+)_to_(\w+)$/)[0]
|
38
|
+
end
|
39
|
+
|
40
|
+
def legal_conversion?(from, to)
|
41
|
+
self::CONVERSIONS.include?(from.to_sym) &&
|
42
|
+
self::CONVERSIONS.include?(to.to_sym)
|
43
|
+
end
|
44
|
+
|
25
45
|
def define_conversion(from, to)
|
26
|
-
return false if not self::CONVERSIONS[from.to_sym]
|
27
|
-
return false if not self::CONVERSIONS[to.to_sym]
|
28
46
|
self.class.instance_exec do
|
29
|
-
define_method("#{
|
47
|
+
define_method("#{from}_to_#{to}") do |value|
|
30
48
|
convert(from.to_sym, to.to_sym, value)
|
31
49
|
end
|
32
50
|
end
|
33
|
-
|
51
|
+
end
|
52
|
+
|
53
|
+
def legal_constructor?(name)
|
54
|
+
self::CONVERSIONS.include?(name.to_sym)
|
34
55
|
end
|
35
56
|
|
36
57
|
# Define klass.unit(value) which converts the parameter
|
37
58
|
# from the unit and returns an instance
|
38
59
|
def define_constructor(name)
|
39
|
-
return false if not self::CONVERSIONS[name.to_sym]
|
40
60
|
self.class.instance_exec do
|
41
|
-
define_method(
|
42
|
-
new(
|
61
|
+
define_method(name.to_sym) do |*args|
|
62
|
+
new(args[0].to_f / self::CONVERSIONS[name])
|
43
63
|
end
|
44
64
|
end
|
45
65
|
end
|
@@ -55,20 +75,21 @@ module M9t
|
|
55
75
|
end
|
56
76
|
end
|
57
77
|
|
58
|
-
# Returns the
|
78
|
+
# Returns the class's current options - see the specific class for
|
79
|
+
# defaults
|
59
80
|
def options
|
60
81
|
@options
|
61
82
|
end
|
62
83
|
|
63
|
-
# Reloads the class
|
84
|
+
# Reloads the class"s default options
|
64
85
|
def reset_options!
|
65
|
-
@options = self::DEFAULT_OPTIONS.clone
|
86
|
+
@options = self::DEFAULT_OPTIONS.clone
|
66
87
|
end
|
67
88
|
|
68
89
|
# The name used for i18n translations
|
69
|
-
# M9t::Distance =>
|
90
|
+
# M9t::Distance => "distance"
|
70
91
|
def measurement_name
|
71
|
-
name.split(
|
92
|
+
name.split("::")[-1].downcase
|
72
93
|
end
|
73
94
|
|
74
95
|
def default_unit
|
@@ -86,51 +107,73 @@ module M9t
|
|
86
107
|
end
|
87
108
|
|
88
109
|
attr_reader :value, :options
|
89
|
-
|
110
|
+
alias_method :to_f, :value
|
90
111
|
|
91
|
-
def initialize(
|
112
|
+
def initialize(value)
|
92
113
|
@value = value.to_f
|
93
114
|
end
|
94
115
|
|
95
116
|
# define conversion instance methods as required
|
96
117
|
def method_missing(name, *args, &block)
|
97
|
-
|
98
|
-
|
118
|
+
to = extract_to(name)
|
119
|
+
if to && legal_conversion?(to)
|
120
|
+
define_conversion(to)
|
121
|
+
return send(name)
|
99
122
|
end
|
100
|
-
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def respond_to?(name, _include_all = false)
|
127
|
+
to = extract_to(name)
|
128
|
+
return true if to && legal_conversion?(to)
|
129
|
+
super
|
101
130
|
end
|
102
131
|
|
103
132
|
# Returns the string representation of the measurement,
|
104
133
|
# taking into account locale, desired units and abbreviation.
|
105
|
-
def to_s(
|
106
|
-
options = self.class.options.merge(
|
107
|
-
|
108
|
-
|
109
|
-
|
134
|
+
def to_s(options = {})
|
135
|
+
options = self.class.options.merge(options)
|
136
|
+
unless self.class::CONVERSIONS.include?(options[:units])
|
137
|
+
units_error(options[:units])
|
138
|
+
end
|
139
|
+
value_in_units = send("to_#{options[:units]}")
|
140
|
+
localized_value = I18n.localize_float(
|
141
|
+
value_in_units, format: "%0.#{options[:precision]}f"
|
142
|
+
)
|
110
143
|
|
111
|
-
key =
|
112
|
-
|
113
|
-
unit = I18n.t(key, {:count => value_in_units})
|
144
|
+
key = i18n_key(options)
|
145
|
+
unit = I18n.t(key, count: value_in_units)
|
114
146
|
|
115
|
-
"#{
|
147
|
+
"#{localized_value}%s#{unit}" % (options[:abbreviated] ? "" : " ")
|
116
148
|
end
|
117
149
|
|
118
150
|
private
|
119
151
|
|
152
|
+
def i18n_key(options = {})
|
153
|
+
key = "units.#{self.class.measurement_name}.#{options[:units]}"
|
154
|
+
key += options[:abbreviated] ? ".abbreviated" : ".full"
|
155
|
+
key
|
156
|
+
end
|
157
|
+
|
120
158
|
def units_error(units)
|
121
|
-
|
159
|
+
known = self.class::CONVERSIONS.keys.collect(&:to_s).join(", ")
|
160
|
+
fail M9t::UnitError, %Q(Unknown units "#{units}". Known: #{known})
|
161
|
+
end
|
162
|
+
|
163
|
+
def extract_to(name)
|
164
|
+
name.to_s[/^to_(\w+)$/, 1]
|
165
|
+
end
|
166
|
+
|
167
|
+
def legal_conversion?(to)
|
168
|
+
self.class::CONVERSIONS.include?(to.to_sym)
|
122
169
|
end
|
123
170
|
|
124
171
|
def define_conversion(to)
|
125
|
-
return false if not self.class::CONVERSIONS[to.to_sym]
|
126
172
|
self.class.instance_exec do
|
127
|
-
define_method("to_#{
|
128
|
-
self.class.convert(self.class.default_unit, to.to_sym,
|
173
|
+
define_method("to_#{to}") do
|
174
|
+
self.class.convert(self.class.default_unit, to.to_sym, to_f)
|
129
175
|
end
|
130
176
|
end
|
131
|
-
true
|
132
177
|
end
|
133
|
-
|
134
178
|
end
|
135
|
-
|
136
179
|
end
|
data/lib/m9t/direction.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
|
-
|
2
|
-
require 'i18n'
|
1
|
+
require "m9t/base"
|
3
2
|
|
4
3
|
module M9t
|
5
|
-
|
6
4
|
# Represents a geographical direction
|
7
5
|
class Direction
|
8
|
-
DEFAULT_OPTIONS = {:
|
9
|
-
CONVERSIONS
|
10
|
-
:
|
11
|
-
:
|
6
|
+
DEFAULT_OPTIONS = {units: :degrees, abbreviated: false, decimals: 5}
|
7
|
+
CONVERSIONS = {
|
8
|
+
degrees: 1.0,
|
9
|
+
compass: nil,
|
12
10
|
}
|
13
11
|
|
14
12
|
# Conversions
|
@@ -18,39 +16,35 @@ module M9t
|
|
18
16
|
include M9t::Base
|
19
17
|
|
20
18
|
class << self
|
21
|
-
|
22
19
|
# Given a value in degrees, returns the nearest (localized) compass direction
|
23
|
-
# M9t::Directions.to_compass(42) =>
|
20
|
+
# M9t::Directions.to_compass(42) => "NE"
|
24
21
|
def degrees_to_compass(degrees)
|
25
22
|
sector = (normalize(degrees) / COMPASS_SECTOR_DEGREES).round
|
26
|
-
I18n.t(self.measurement_name +
|
23
|
+
I18n.t(self.measurement_name + ".sectors")[sector]
|
27
24
|
end
|
28
25
|
|
29
26
|
def compass_to_degrees(compass_direction)
|
30
27
|
compass(compass_direction).to_f
|
31
28
|
end
|
32
29
|
|
33
|
-
# Accepts a localized compass direction (e.g.
|
34
|
-
# M9t::Direction.compass(
|
30
|
+
# Accepts a localized compass direction (e.g. "N") and returns the equivalent M9t::Direction
|
31
|
+
# M9t::Direction.compass("NE") => #<M9t::Direction:0x000000014a438618 @value=45.0>
|
35
32
|
def compass(compass_direction)
|
36
|
-
sector = I18n.t(self.measurement_name +
|
37
|
-
raise "Compass direction '#{
|
33
|
+
sector = I18n.t(self.measurement_name + ".sectors").find_index(compass_direction)
|
34
|
+
raise "Compass direction '#{compass_direction}' not recognised" if sector.nil?
|
38
35
|
new(sector.to_f * COMPASS_SECTOR_DEGREES)
|
39
36
|
end
|
40
37
|
|
41
38
|
# Reduce directions in degrees to the range [0, 360)
|
42
39
|
# M9t::Direction.normalize(1000) => 280.0
|
43
40
|
def normalize(degrees)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
when degrees >= CIRCLE
|
48
|
-
normalize(degrees - CIRCLE)
|
41
|
+
remainder = degrees.remainder(CIRCLE)
|
42
|
+
if remainder < 0
|
43
|
+
remainder + CIRCLE
|
49
44
|
else
|
50
|
-
|
45
|
+
remainder
|
51
46
|
end
|
52
47
|
end
|
53
|
-
|
54
48
|
end
|
55
49
|
|
56
50
|
# Handles the special case where compass directions are the desired output.
|
@@ -65,7 +59,5 @@ module M9t
|
|
65
59
|
def to_compass
|
66
60
|
self.class.degrees_to_compass(@value)
|
67
61
|
end
|
68
|
-
|
69
62
|
end
|
70
|
-
|
71
63
|
end
|