m9t 0.3.3 → 0.3.4
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.
- data/Gemfile +2 -1
- data/README.md +25 -10
- data/Rakefile +11 -24
- data/lib/m9t/base.rb +62 -19
- data/lib/m9t/version.rb +1 -1
- data/locales/en.yml +13 -0
- data/m9t.gemspec +9 -2
- data/spec/spec_helper.rb +23 -0
- data/spec/unit/base_spec.rb +53 -0
- data/spec/unit/direction_spec.rb +185 -0
- data/spec/unit/distance_spec.rb +129 -0
- data/spec/unit/i18n_spec.rb +56 -0
- data/spec/unit/pressure_spec.rb +24 -0
- data/spec/unit/speed_spec.rb +104 -0
- data/spec/unit/temperature_spec.rb +111 -0
- metadata +29 -20
- 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 -42
- 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
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -42,31 +42,41 @@ Interface | |
| 42 42 |  | 
| 43 43 | 
             
            new: accepts the S.I. unit as a parameter:
         | 
| 44 44 |  | 
| 45 | 
            -
             | 
| 45 | 
            +
            ```ruby
         | 
| 46 | 
            +
            height = M9t::Distance.new(1.75)
         | 
| 47 | 
            +
            ```
         | 
| 46 48 |  | 
| 47 49 | 
             
            to_f: returns the decimal value(s):
         | 
| 48 50 |  | 
| 49 | 
            -
             | 
| 51 | 
            +
            ```ruby
         | 
| 52 | 
            +
            height.to_f -> 1.75
         | 
| 53 | 
            +
            ```
         | 
| 50 54 |  | 
| 51 55 | 
             
            other units:
         | 
| 52 56 | 
             
            there are class methods named after each known unit,
         | 
| 53 57 | 
             
            which take values in that unit
         | 
| 54 58 | 
             
            (actually, they are defined as needed):
         | 
| 55 59 |  | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 60 | 
            +
            ```ruby
         | 
| 61 | 
            +
            marathon = M9t::Distance.miles(26.21875)
         | 
| 62 | 
            +
            marathon.to_f -> 42194.988
         | 
| 63 | 
            +
            ```
         | 
| 58 64 |  | 
| 59 65 | 
             
            to_s: returns a localized string with units:
         | 
| 60 66 |  | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 67 | 
            +
            ```ruby
         | 
| 68 | 
            +
            I18n.locale = :it
         | 
| 69 | 
            +
            puts M9t::Distance.new(3).to_s -> '3 metri'
         | 
| 70 | 
            +
            ```
         | 
| 63 71 |  | 
| 64 72 | 
             
            Class methods for conversion
         | 
| 65 73 | 
             
            ============================
         | 
| 66 74 |  | 
| 67 75 | 
             
            Methods are available for conversion between any pair of units:
         | 
| 68 76 |  | 
| 69 | 
            -
             | 
| 77 | 
            +
            ```ruby
         | 
| 78 | 
            +
            M9t::Distance.miles_to_meters(26.21875) -> 42194.988
         | 
| 79 | 
            +
            ```
         | 
| 70 80 |  | 
| 71 81 | 
             
            Testing
         | 
| 72 82 | 
             
            =======
         | 
| @@ -74,13 +84,17 @@ Testing | |
| 74 84 | 
             
            Coverage
         | 
| 75 85 | 
             
            --------
         | 
| 76 86 |  | 
| 77 | 
            -
            ruby 1.8.x:
         | 
| 87 | 
            +
            ruby 1.8.x (not jruby):
         | 
| 78 88 |  | 
| 79 | 
            -
             | 
| 89 | 
            +
            ```shell
         | 
| 90 | 
            +
            $ rake rcov
         | 
| 91 | 
            +
            ```
         | 
| 80 92 |  | 
| 81 93 | 
             
            ruby 1.9.x:
         | 
| 82 94 |  | 
| 83 | 
            -
             | 
| 95 | 
            +
            ```shell
         | 
| 96 | 
            +
            $ COVERAGE=1 rake test
         | 
| 97 | 
            +
            ```
         | 
| 84 98 |  | 
| 85 99 | 
             
            Alternatives
         | 
| 86 100 | 
             
            ============
         | 
| @@ -104,3 +118,4 @@ Dual license: | |
| 104 118 |  | 
| 105 119 | 
             
            - MIT License: see MIT-LICENSE.txt,
         | 
| 106 120 | 
             
            - GPL version 3: see GPL-LICENSE.txt
         | 
| 121 | 
            +
             | 
    
        data/Rakefile
    CHANGED
    
    | @@ -1,32 +1,19 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require ' | 
| 1 | 
            +
            #!/usr/bin/env rake
         | 
| 2 | 
            +
            require 'bundler/gem_tasks'
         | 
| 3 | 
            +
            require 'rcov/rcovtask' if RUBY_VERSION < '1.9'
         | 
| 4 | 
            +
            require 'rspec/core/rake_task'
         | 
| 3 5 |  | 
| 4 | 
            -
             | 
| 5 | 
            -
            require 'm9t'
         | 
| 6 | 
            +
            task :default => :spec
         | 
| 6 7 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
            Rake::TestTask.new do |t|
         | 
| 10 | 
            -
              t.libs       << 'test'
         | 
| 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 11 |  | 
| 15 12 | 
             
            if RUBY_VERSION < '1.9'
         | 
| 16 | 
            -
               | 
| 17 | 
            -
             | 
| 18 | 
            -
                t. | 
| 19 | 
            -
                t.rcov_opts | 
| 13 | 
            +
              RSpec::Core::RakeTask.new('spec:rcov') do |t|
         | 
| 14 | 
            +
                t.pattern   = 'spec/**/*_spec.rb'
         | 
| 15 | 
            +
                t.rcov      = true
         | 
| 16 | 
            +
                t.rcov_opts = ['--exclude', 'spec/,/gems/']
         | 
| 20 17 | 
             
              end
         | 
| 21 18 | 
             
            end
         | 
| 22 19 |  | 
| 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/base.rb
    CHANGED
    
    | @@ -2,41 +2,67 @@ | |
| 2 2 | 
             
            require 'i18n'
         | 
| 3 3 |  | 
| 4 4 | 
             
            module M9t
         | 
| 5 | 
            -
             | 
| 6 5 | 
             
              module Base
         | 
| 7 | 
            -
             | 
| 8 6 | 
             
                def self.generate_conversions(klass)
         | 
| 9 7 | 
             
                  klass.instance_eval do |klass|
         | 
| 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])
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
                      super
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def respond_to?(name, include_all = false)
         | 
| 29 | 
            +
                      from, to = extract_from_and_to(name)
         | 
| 30 | 
            +
                      if from
         | 
| 31 | 
            +
                        return true if legal_conversion?(from, to)
         | 
| 18 32 | 
             
                      end
         | 
| 19 | 
            -
                      return  | 
| 20 | 
            -
                       | 
| 33 | 
            +
                      return legal_constructor?(name)
         | 
| 34 | 
            +
                      super
         | 
| 21 35 | 
             
                    end
         | 
| 22 36 |  | 
| 23 37 | 
             
                    private
         | 
| 24 38 |  | 
| 39 | 
            +
                    def extract_from_and_to(name)
         | 
| 40 | 
            +
                      if name.to_s =~ /^(\w+)_to_(\w+)$/
         | 
| 41 | 
            +
                        [$1, $2]
         | 
| 42 | 
            +
                      else
         | 
| 43 | 
            +
                        nil
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def legal_conversion?(from, to)
         | 
| 48 | 
            +
                      self::CONVERSIONS.include?(from.to_sym) and self::CONVERSIONS.include?(to.to_sym)
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 25 51 | 
             
                    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 52 | 
             
                      self.class.instance_exec do
         | 
| 29 53 | 
             
                        define_method("#{ from }_to_#{ to }") do |value|
         | 
| 30 54 | 
             
                          convert(from.to_sym, to.to_sym, value)
         | 
| 31 55 | 
             
                        end
         | 
| 32 56 | 
             
                      end
         | 
| 33 | 
            -
             | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    def legal_constructor?(name)
         | 
| 60 | 
            +
                      self::CONVERSIONS.include?(name.to_sym)
         | 
| 34 61 | 
             
                    end
         | 
| 35 62 |  | 
| 36 63 | 
             
                    # Define klass.unit(value) which converts the parameter
         | 
| 37 64 | 
             
                    # from the unit and returns an instance
         | 
| 38 65 | 
             
                    def define_constructor(name)
         | 
| 39 | 
            -
                      return false if not self::CONVERSIONS[name.to_sym]
         | 
| 40 66 | 
             
                      self.class.instance_exec do
         | 
| 41 67 | 
             
                        define_method( name.to_sym ) do | *args |
         | 
| 42 68 | 
             
                          new( args[ 0 ].to_f / self::CONVERSIONS[ name ] )
         | 
| @@ -94,10 +120,18 @@ module M9t | |
| 94 120 |  | 
| 95 121 | 
             
                # define conversion instance methods as required
         | 
| 96 122 | 
             
                def method_missing(name, *args, &block)
         | 
| 97 | 
            -
                   | 
| 98 | 
            -
             | 
| 123 | 
            +
                  to = extract_to(name)
         | 
| 124 | 
            +
                  if to and legal_conversion?(to)
         | 
| 125 | 
            +
                    define_conversion(to)
         | 
| 126 | 
            +
                    return send(name)
         | 
| 99 127 | 
             
                  end
         | 
| 100 | 
            -
                   | 
| 128 | 
            +
                  super
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def respond_to?(name, include_all = false)
         | 
| 132 | 
            +
                  to = extract_to(name)
         | 
| 133 | 
            +
                  return true if to and legal_conversion?(to)
         | 
| 134 | 
            +
                  super
         | 
| 101 135 | 
             
                end
         | 
| 102 136 |  | 
| 103 137 | 
             
                # Returns the string representation of the measurement,
         | 
| @@ -121,16 +155,25 @@ module M9t | |
| 121 155 | 
             
                  raise M9t::UnitError.new("Unknown units '#{ units }'. Known: #{ self.class::CONVERSIONS.keys.collect{|unit| unit.to_s}.join(', ') }")
         | 
| 122 156 | 
             
                end
         | 
| 123 157 |  | 
| 158 | 
            +
                def extract_to(name)
         | 
| 159 | 
            +
                  if name.to_s =~ /^to_(\w+)$/
         | 
| 160 | 
            +
                    $1
         | 
| 161 | 
            +
                  else
         | 
| 162 | 
            +
                    nil
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                def legal_conversion?(to)
         | 
| 167 | 
            +
                  self.class::CONVERSIONS.include?(to.to_sym)
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 124 170 | 
             
                def define_conversion(to)
         | 
| 125 | 
            -
                  return false if not self.class::CONVERSIONS[to.to_sym]
         | 
| 126 171 | 
             
                  self.class.instance_exec do
         | 
| 127 | 
            -
                    define_method("to_#{ | 
| 172 | 
            +
                    define_method("to_#{to}") do
         | 
| 128 173 | 
             
                      self.class.convert(self.class.default_unit, to.to_sym, self.to_f)
         | 
| 129 174 | 
             
                    end
         | 
| 130 175 | 
             
                  end
         | 
| 131 | 
            -
                  true
         | 
| 132 176 | 
             
                end
         | 
| 133 | 
            -
             | 
| 134 177 | 
             
              end
         | 
| 135 | 
            -
             | 
| 136 178 | 
             
            end
         | 
| 179 | 
            +
             | 
    
        data/lib/m9t/version.rb
    CHANGED
    
    
    
        data/locales/en.yml
    CHANGED
    
    | @@ -22,6 +22,7 @@ en: | |
| 22 22 | 
             
                      zero: miles
         | 
| 23 23 | 
             
                      one: mile
         | 
| 24 24 | 
             
                      other: miles
         | 
| 25 | 
            +
                    abbreviated: mi
         | 
| 25 26 | 
             
                  feet:
         | 
| 26 27 | 
             
                    full:
         | 
| 27 28 | 
             
                      one: foot
         | 
| @@ -35,6 +36,12 @@ en: | |
| 35 36 | 
             
                      other: degrees
         | 
| 36 37 | 
             
                    abbreviated: °
         | 
| 37 38 | 
             
                speed:
         | 
| 39 | 
            +
                  miles_per_hour:
         | 
| 40 | 
            +
                    full:
         | 
| 41 | 
            +
                      zero: miles per hour
         | 
| 42 | 
            +
                      one: mile per hour
         | 
| 43 | 
            +
                      other: miles per hour
         | 
| 44 | 
            +
                    abbreviated: mph
         | 
| 38 45 | 
             
                  meters_per_second:
         | 
| 39 46 | 
             
                    full:
         | 
| 40 47 | 
             
                      zero: meters per second
         | 
| @@ -52,6 +59,12 @@ en: | |
| 52 59 | 
             
                      one: knot
         | 
| 53 60 | 
             
                      other: knots
         | 
| 54 61 | 
             
                temperature:
         | 
| 62 | 
            +
                  fahrenheit:
         | 
| 63 | 
            +
                    full:
         | 
| 64 | 
            +
                      zero: degrees
         | 
| 65 | 
            +
                      one: degree
         | 
| 66 | 
            +
                      other: degrees
         | 
| 67 | 
            +
                    abbreviated: °F
         | 
| 55 68 | 
             
                  degrees:
         | 
| 56 69 | 
             
                    full:
         | 
| 57 70 | 
             
                      zero: degrees
         | 
    
        data/m9t.gemspec
    CHANGED
    
    | @@ -23,6 +23,13 @@ gemspec = Gem::Specification.new do |s| | |
| 23 23 | 
             
              s.add_dependency 'rake'
         | 
| 24 24 | 
             
              s.add_dependency 'i18n', '>= 0.3.5'
         | 
| 25 25 |  | 
| 26 | 
            -
              s.add_development_dependency ' | 
| 27 | 
            -
               | 
| 26 | 
            +
              s.add_development_dependency 'rspec'
         | 
| 27 | 
            +
              if RUBY_VERSION < '1.9'
         | 
| 28 | 
            +
                if RUBY_PLATFORM != 'java'
         | 
| 29 | 
            +
                  s.add_development_dependency 'rcov'
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              else
         | 
| 32 | 
            +
                s.add_development_dependency 'simplecov'
         | 
| 33 | 
            +
              end
         | 
| 28 34 | 
             
            end
         | 
| 35 | 
            +
             | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
         | 
| 2 | 
            +
            require 'rspec'
         | 
| 3 | 
            +
            require 'rspec/autorun'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            if RUBY_VERSION > '1.9'
         | 
| 6 | 
            +
              require 'simplecov'
         | 
| 7 | 
            +
              if ENV['COVERAGE']
         | 
| 8 | 
            +
                SimpleCov.start do
         | 
| 9 | 
            +
                  add_filter '/spec/'
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            require 'm9t'
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            RSpec.configure do |config|
         | 
| 17 | 
            +
              config.treat_symbols_as_metadata_keys_with_true_values = true
         | 
| 18 | 
            +
              config.run_all_when_everything_filtered = true
         | 
| 19 | 
            +
              config.filter_run :focus
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              config.order = 'random'
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            require 'spec_helper'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class SomeMeasurement
         | 
| 5 | 
            +
              DEFAULT_OPTIONS = {
         | 
| 6 | 
            +
                :units       => :foos,
         | 
| 7 | 
            +
                :abbreviated => false,
         | 
| 8 | 
            +
                :decimals    => 1
         | 
| 9 | 
            +
              }
         | 
| 10 | 
            +
              CONVERSIONS = {
         | 
| 11 | 
            +
                :foos =>      1.0,
         | 
| 12 | 
            +
                :bars => 1 / 42.0
         | 
| 13 | 
            +
              }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              include M9t::Base
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            class SomeDerivedMeasurement < SomeMeasurement; end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            describe M9t::Base do
         | 
| 21 | 
            +
              describe '.method_missing' do
         | 
| 22 | 
            +
                it 'handles conversion between known units' do
         | 
| 23 | 
            +
                  expect(SomeMeasurement.foos_to_bars(3.0)).to be_a(Float)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                it 'fails for unknown units' do
         | 
| 27 | 
            +
                  expect {
         | 
| 28 | 
            +
                    SomeMeasurement.bazs_to_bars(3.0)
         | 
| 29 | 
            +
                  }.to raise_error(NoMethodError)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              describe '#method_missing' do
         | 
| 34 | 
            +
                subject { SomeMeasurement.new(3.0) }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                it 'handles conversion to known units' do
         | 
| 37 | 
            +
                  expect(subject.to_bars).to be_a(Float)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                it 'fails for unknown units' do
         | 
| 41 | 
            +
                  expect {
         | 
| 42 | 
            +
                    subject.to_bazs(3.0)
         | 
| 43 | 
            +
                  }.to raise_error(NoMethodError)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              describe 'derived class' do
         | 
| 48 | 
            +
                it 'inherits options' do
         | 
| 49 | 
            +
                  expect(SomeDerivedMeasurement.options).to eq(SomeMeasurement.options)
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| 53 | 
            +
             | 
| @@ -0,0 +1,185 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            require 'spec_helper'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe M9t::Direction do
         | 
| 5 | 
            +
              before do
         | 
| 6 | 
            +
                I18n.locale = :en
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              describe '.measurement_name' do
         | 
| 10 | 
            +
                it "is 'direction'" do
         | 
| 11 | 
            +
                  expect(M9t::Direction.measurement_name).to eq('direction')
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              describe '.options' do
         | 
| 16 | 
            +
                it 'is set' do
         | 
| 17 | 
            +
                  expect(M9t::Direction.options).not_to be_nil
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                context 'abbreviated' do
         | 
| 21 | 
            +
                  it 'is false' do
         | 
| 22 | 
            +
                    expect(M9t::Direction.options[:abbreviated]).to be_false
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                context 'units' do
         | 
| 27 | 
            +
                  it 'is degrees' do
         | 
| 28 | 
            +
                    expect(M9t::Direction.options[:units]).to eq(:degrees)
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              describe '.normalize' do
         | 
| 34 | 
            +
                it 'handles values > 360' do
         | 
| 35 | 
            +
                  expect(M9t::Direction.normalize(725)).to eq(5)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                it 'handles values < 0' do
         | 
| 39 | 
            +
                  expect(M9t::Direction.normalize(-355)).to eq(5)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              context 'conversion class methods' do
         | 
| 44 | 
            +
                describe '.degrees_to_degrees' do
         | 
| 45 | 
            +
                  it 'returns the identity' do
         | 
| 46 | 
            +
                    expect(M9t::Direction.degrees_to_degrees(45)).to eq(45)
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                describe '.degrees_to_compass' do
         | 
| 51 | 
            +
                  before do
         | 
| 52 | 
            +
                    I18n.locale = :en
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  context 'exact' do
         | 
| 56 | 
            +
                    [
         | 
| 57 | 
            +
                      'N', 'NNE', 'NE', 'ENE',
         | 
| 58 | 
            +
                      'E', 'ESE', 'SE', 'SSE',
         | 
| 59 | 
            +
                      'S', 'SSW', 'SW', 'WSW',
         | 
| 60 | 
            +
                      'W', 'WNW', 'NW', 'NNW'
         | 
| 61 | 
            +
                    ].each.with_index do |result, i|
         | 
| 62 | 
            +
                      it "recognizes #{result}" do
         | 
| 63 | 
            +
                        expect(M9t::Direction.degrees_to_compass(i * 22.5)).to eq(result)
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  context 'rounding' do
         | 
| 69 | 
            +
                    specify 'up' do
         | 
| 70 | 
            +
                      expect(M9t::Direction.degrees_to_compass(42)).to eq('NE')
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    specify 'down' do
         | 
| 74 | 
            +
                      expect(M9t::Direction.degrees_to_compass(93)).to eq('E')
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  context 'i18n' do
         | 
| 79 | 
            +
                    before do
         | 
| 80 | 
            +
                      I18n.locale = :it
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    it 'translates' do
         | 
| 84 | 
            +
                      expect(M9t::Direction.degrees_to_compass(270)).to eq('O')
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                describe 'compass_to_degrees' do
         | 
| 90 | 
            +
                  it 'converts correctly' do
         | 
| 91 | 
            +
                    expect(M9t::Direction.compass_to_degrees('WSW')).to eq(247.5)
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              describe '.new' do
         | 
| 97 | 
            +
                context 'strings' do
         | 
| 98 | 
            +
                  it 'works' do
         | 
| 99 | 
            +
                    expect(M9t::Direction.new('35').value).to eq(35)
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  it 'handles leading zeroes' do
         | 
| 103 | 
            +
                    expect(M9t::Direction.new('010').value).to eq(10)
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              describe '.compass' do
         | 
| 109 | 
            +
                it 'converts cardinals' do
         | 
| 110 | 
            +
                  expect(M9t::Direction.compass('N').value).to eq(0)
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                it 'handles 16ths' do
         | 
| 114 | 
            +
                  expect(M9t::Direction.compass('WSW').value).to eq(247.5)
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              describe '#value' do
         | 
| 119 | 
            +
                let(:degrees) { M9t::Direction.new(45) }
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                it 'returns the supplied value' do
         | 
| 122 | 
            +
                  expect(degrees.value).to eq(45)
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              describe '#to_s' do
         | 
| 127 | 
            +
                context 'not abbreviated' do
         | 
| 128 | 
            +
                  context 'singular' do
         | 
| 129 | 
            +
                    subject { M9t::Direction.new(1) }
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                    it 'returns the full unit name' do
         | 
| 132 | 
            +
                      expect(subject.to_s).to eq('1 degree')
         | 
| 133 | 
            +
                    end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                    it 'translates' do
         | 
| 136 | 
            +
                      I18n.locale = :it
         | 
| 137 | 
            +
                      expect(subject.to_s).to eq('1 grado')
         | 
| 138 | 
            +
                    end
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  context 'plural' do
         | 
| 142 | 
            +
                    subject { M9t::Direction.new(135) }
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                    it 'returns the full unit name' do
         | 
| 145 | 
            +
                      expect(subject.to_s).to eq('135 degrees')
         | 
| 146 | 
            +
                    end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                    it 'translates' do
         | 
| 149 | 
            +
                      I18n.locale = :it
         | 
| 150 | 
            +
                      expect(subject.to_s).to eq('135 gradi')
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                context 'abbreviated' do
         | 
| 156 | 
            +
                  subject { M9t::Direction.new(135) }
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  it 'uses the symbol' do
         | 
| 159 | 
            +
                    expect(subject.to_s(:abbreviated => true)).to eq('135°')
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                context 'compass units' do
         | 
| 164 | 
            +
                  subject { M9t::Direction.new(225) }
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  it 'works' do
         | 
| 167 | 
            +
                    expect(subject.to_s(:units => :compass)).to eq('SW')
         | 
| 168 | 
            +
                  end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                  it 'translates' do
         | 
| 171 | 
            +
                    I18n.locale = :it
         | 
| 172 | 
            +
                    expect(subject.to_s(:units => :compass)).to eq('SO')
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
              end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
              describe '#to_compass' do
         | 
| 178 | 
            +
                subject { M9t::Direction.new(0) }
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                it 'is correct' do
         | 
| 181 | 
            +
                  expect(subject.to_compass).to eq('N')
         | 
| 182 | 
            +
                end
         | 
| 183 | 
            +
              end
         | 
| 184 | 
            +
            end
         | 
| 185 | 
            +
             |