Giter Site home page Giter Site logo

alchemist's Introduction

Alchemist

Build Status Code Climate

Doing conversions for you so you don’t have to google them and making code more readable.

Having code that looks like this is meaningless

meters = 8 * 1609.344

You could add comments

meters = 8 * 1609.344 # converting miles to meters

But why not have this!

8.miles.to.meters

You can even perform mathematical operations

10.kilometers + 1.mile # 11.609344 kilometers

Handling bytes now works according to the JEDEC memory standard

1.kb.to.b.to_f == 1024.0

Converting distance of arc length on Earth to an (approximate) corresponding spherical geometry angle can be done with

require 'alchemist/geospatial'
1.mile.geospatial.to.degree == 0.014457066992474555

To switch to the IEC memory standard, force SI units with

Alchemist.config.use_si = true

To see all the units alchemist has built in conversion for, check out the units file

You may also register your own units

Alchemist.register(:distance, [:beard_second, :beard_seconds], 5.angstroms)

Installation

gem install alchemist

Setup

In order for methods like 1.meter to work, you'll either need to setup Alchemist yourself:

Alchemist.setup # This will load every category of measurement

if you only want to use one category for conversions you can load it individually:

Alchemist.setup('distance') # This will load only distance

Rails

Setup

It is suggested that you add your Alchemist.setup call to config/initializers/alchemist.rb and then restart your rails server.

Rails Warning

Rails adds some methods like bytes to Numeric so it's highly recommended that instead of trying to call bytes on a numeric, you should use the measure method:

Alchemist.measure(10, :bytes)

License

Alchemist is licensed under the MIT license as specified in the gemspec

alchemist's People

Contributors

ahorner avatar anujbiyani avatar brunopgalvao avatar derekprior avatar erithmetic avatar fd avatar halogenandtoast avatar janjiss avatar muff1nman avatar nebelhut avatar shenry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

alchemist's Issues

#round does not work on Measurements

As of version 1.6, methods like #round, #floor, #ceil no longer work on converted numbers.

e.g. 10.4.celsius.round

NoMethodError: undefined method `round' for 10.4:Alchemist::Measurement

Weird conversions

Hi!
Maybe I'm missing something, but I get this weird conversion:

2.0.0p247 :014 > 1.kg.to.kg
 => #<Alchemist::Measurement:0x007fbe66c34d68 @value=1000.0, @unit_name=:g, @exponent=1000.0>
2.0.0p247 :015 > 1.kg.to.kg.to_i
 => 1000

Tests currently failing under Ruby 1.9

Haven't looked too closely at this yet, but the tests are failing in Ruby 1.9:

test_temperature(AlchemistTest):
ArgumentError: comparison of Float with Alchemist::NumericConversion failed
    /Users/johnduff/development/workspace/alchemist/test/alchemist_test.rb:77:in `test_temperature

I also noticed that in Ruby 1.9 instead of getting:

>> 5.grams
=> #<Alchemist::NumericConversion:0x101227188 @exponent=1.0, @unit_name=:grams, @value=5.0> #ruby 1.8 output

You get:

>> 5.grams
=> 5.0 # ruby 1.9 output

gigahz (or *hz) fails

Seems that hz.to returns FLOAT Object only. Not sure why (I'm new to ruby) or else I'd help with my own code.

Thanks for the cool library!

undefined method `setup' for Alchemist:Module (NoMethodError)

Hello! I added an initializer to my rails app (config/initializers/alchemist.rb) with the following:

Alchemist.setup('distance') 

I'm using alchemist (0.1.5)

undefined method `setup' for Alchemist:Module (NoMethodError)
/Users/mvazquez/work/Jiff3/config/initializers/alchemist.rb:1:in `<top (required)>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `block in load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:236:in `load_dependency'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/engine.rb:588:in `block (2 levels) in <class:Engine>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/engine.rb:587:in `each'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/engine.rb:587:in `block in <class:Engine>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/initializable.rb:30:in `instance_exec'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/initializable.rb:30:in `run'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/initializable.rb:55:in `block in run_initializers'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/initializable.rb:54:in `each'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/initializable.rb:54:in `run_initializers'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/application.rb:136:in `initialize!'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/railties-3.2.13/lib/rails/railtie/configurable.rb:30:in `method_missing'
/Users/mvazquez/work/Jiff3/config/environment.rb:11:in `<top (required)>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:251:in `require'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:251:in `block in require'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:236:in `load_dependency'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:251:in `require'
/Users/mvazquez/work/Jiff3/spec/spec_helper.rb:10:in `block in <top (required)>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork.rb:24:in `prefork'
/Users/mvazquez/work/Jiff3/spec/spec_helper.rb:3:in `<top (required)>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `block in load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:236:in `load_dependency'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:245:in `load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork/test_framework.rb:138:in `block (2 levels) in preload'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-rails-3.2.1/lib/spork/app_framework/rails.rb:8:in `preload'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork/test_framework.rb:134:in `block in preload'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork.rb:62:in `exec_prefork'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork/test_framework.rb:120:in `preload'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork/run_strategy/forking.rb:25:in `preload'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork/runner.rb:74:in `run'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/lib/spork/runner.rb:10:in `run'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/gems/spork-1.0.0rc3/bin/spork:10:in `<top (required)>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/bin/spork:19:in `load'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/bin/spork:19:in `<main>'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/bin/ruby_noexec_wrapper:14:in `eval'
/Users/mvazquez/.rvm/gems/ruby-1.9.3-p392@jiff-jiff3/bin/ruby_noexec_wrapper:14:in `<main>'

Thanks!

Temperature conversions and floating points

Some things I noticed while working with this gem

>> 22.5.celsius.to.fahrenheit
=> 72.4999999999999
>> 22.5.celsius.to.fahrenheit.round
=> 72 # expected be 73

I believe this is equivalent to:

>> (22.5+273.15)*(9.0/5.0)-459.67
=> 72.4999999999999

However, if the conversion is structured slightly different the floating point anomaly disappears:

>> ((22.5+273.15)-273.15)*(9.0/5.0)+32.0
=> 72.5

This floating point anomaly is not present in larger values

>> 222.5.celsius.to.fahrenheit
=> 432.5

Here are some other examples

>> 72.fahrenheit.to.celsius.to_f.celsius.to.fahrenheit
=> 72.0000000000001

>> 1.fahrenheit.to.celsius.to_f.celsius.to.fahrenheit
=> 1.00000000000006

>> 45.0.celsius.to.fahrenheit.to_f
=> 113.0
>> 45.0.celsius.to.fahrenheit.to_f.truncate
=> 112

I think this would work...

:fahrenheit => [Proc.new{ |t| (t - 32.0) * (5.0/9.0) + 273.15}, Proc.new{ |t| (t - 273.15) * (9.0/5.0) + 32.0 }]

Adding gives unexpected results

Love the look of this gem...

But when I do the following:

(1.foot + 1.foot).to.inches

i get this result:

24.000000000000004

is this as expected? units confuse the *** out of me

thanks

Unexpected performance degradation with alchemist

The way alchemist utilizes method_missing seems to result in a fairly significant performance hit when numbers are used in certain ways. The problems can crop up even when you're not intending to use alchemist, so this can be quite unexpected. For example, time parsing can become 10x slower just by having alchemist installed.

Without alchemist, parsing 100,000 time strings takes 3.7 seconds

irb(main):001:0> require "time"; require "benchmark"
=> true
irb(main):002:0> puts Benchmark.measure { 100000.times { Time.parse("2012-01-01 01:01:01") } }
  3.740000   0.010000   3.750000 (  3.738171)

With alchemist, parsing 100,000 time strings takes 43 seconds

irb(main):001:0> require "time"; require "benchmark"; require "alchemist"
=> true
irb(main):002:0> puts Benchmark.measure { 100000.times { Time.parse("2012-01-01 01:01:01") } }
 42.890000   0.430000  43.320000 ( 43.322304)

This seems to largely stem from something in Time.parse calling to_str on a bunch of numeric objects. This method doesn't exist, but with alchemist's method_missing implementation, each to_str call incurs more of an overhead.

I didn't do further debugging to see if there are similar performance consequences outside of this time parsing example, but it seems like a possibility. After removing alchemist from our app, we saw pretty significant speed increases throughout the computationally heavy parts of our app (Rails requests that were taking 30 seconds to process now take 5 seconds).

I'm unsure of any simple fixes given the current dependency on method_missing. But I saw you recently started a rewrite branch, so maybe this is something to consider as you rewrite? Sorry I don't have any fixes, but I wanted to file this as an FYI, since anyone dealing with lots of data might be having similar performance problems in their apps without even realizing it.

If anyone's interested, we ended up switching to m9t for our conversions. It isn't quite as syntactically elegant as alchemist, but it doesn't interfere and slow down unrelated aspects of our application, and it also seems to be the fastest conversion library I could find.

Byte conversion incorrect

Hi, please excuse me, but I'm having issues performing byte conversion.

Your README.md states:

1.kb.to.b.to_f == 1024.0

This evaluates to false for me:

irb(main):010:0> 1.kb.to.b.to_f
=> 999.9999999999999

Feature - convert string to number

In my code I have usecases like this:

walk_data[:distance] = "2"
walk_data[:distance].to_f.meters.to.feet.to_f

This does not look good at all, maybe we can add functionality that provides automatic string conversion to measurment values? If yes, I will look at the code and try to write implementation for that.

Cheers

Relative units

Sometimes to convert a unit to another one you need a third value. What I have in mind is CSS units. For example, if you want to convert inch to em you need to provide the relevant font size. I don't have any other use case in mind, but surely there are.

Do you have in mind to allow relative units in alchemist? I have taken a quick look at how your library works, and maybe for relative units something like that could be implemented:

Alchemist.register :distance, [:em] do |value, relevant_font_size|
  value/relevant_font_size
end

3.inches.to.em.relative_to(12.inch)

What do you think about it? Would you accept a pull request with it? (I'm not sure I would do it, I'm looking at others gems, too, and I haven't decided yet which one to use)

Thanks a lot. This gems seems really easy to use.

Cannot register measurement using Alchemist.register

Tested with Ruby 2.0.0p451 and Ruby 2.1.1p76

Alchemist.reset! also does not work, although other class methods do (.setup, .measure).

irb(main):001:0> require 'alchemist'
=> true
irb(main):002:0> Alchemist.register
NoMethodError: undefined method `register' for Alchemist:Module
    from (irb):2
    from /home/jph/.rbenv/versions/2.0.0-p451/bin/irb:12:in `<main>'
irb(main):003:0> Alchemist.reset!
NoMethodError: undefined method `reset!' for Alchemist:Module
    from (irb):3
    from /home/jph/.rbenv/versions/2.0.0-p451/bin/irb:12:in `<main>'

Weird operation behaviors

I'm not sure I understand why anyone would want this kind of behavior:

height = 69.in
height #=> 69.0
height + 1 #=> 70.0
height #=> 70.0
height - 1 #=> 69.0
height #=> 69.0
height * 2 #=> 138.0
height #=> 138.0
height / 2 #=> 69.0
height #=> 69.0

Why are the +, -, *, and / operators acting like their +=, -=, *=, and /= counterparts?

I discovered this while I was trying to write a method that takes a height, like 69.in, and displays it as 5'9". Seemed like a straightforward problem:

def display_height(height)
  "#{height.to_i/12}'#{height.to_i%12}\""
end

Except that the height variable keeps changing on me. So it looks like the only way around it right now is to set height = height.value.to_i, which will give me good ol' Fixnum back instead of an Alchemist::NumericConversion.

Fixnum dividend breaks division

The specific use case I'm thinking of is averaging. There are simple ways around it, but it might be useful to support this way:

Say you have some input of mixed unit

total = 0.celsius + 32.fahrenheit

If you try to divide by the count:
total / 2

You get NoMethodError: undefined methodunit_name' for 2:Fixnum
from lib/alchemist/measurement.rb:93:in ensure_shared_type!'

If you think it makes sense to support this, I'm happy to look into and doing a pull request.

Adding Rates.

Hey There.

Love the Alchemist gem so far.

We're going to be using it as a platform for converting different rates, for example:

Cubic Feet / Minute ---- to ----> Cubic Meters / Hour

Can you suggest a good way to get started.

Many Thanks!

Josh

Alchemist.register broken in recent version

I'm getting a no method error when trying to register new units

irb(main):005:0> Alchemist.register(:volume, [:dash, :dashs], 0.125.teaspoons)
NoMethodError: undefined method `register' for Alchemist:Module
    from (irb):5
    from /usr/local/var/rbenv/versions/2.0.0-p247/bin/irb:12:in `<main>'

#coerce TypeError

test.rb:17:in +': coerce must return [x, y] (TypeError) from test.rb:17:inblock in

'
from test.rb:16:in each' from test.rb:16:infind'
from test.rb:16:in `'

totalRAM = 0
hosts = cluster.host.grep(RbVmomi::VIM::HostSystem).find do |host|
  totalRAM += host.hardware.memorySize.bytes.to.gigabytes
end
puts "Total RAM (GB): ", totalRAM

Better to_s

Right now, alchemist provides very basic to_s methods. In the case of a simple measurement, they simply convert the float version of the measurement to a string:

irb(main):003:0> 1.meter.to_s
=> "1.0"
irb(main):004:0> 3.seconds.to_s
=> "3.0"

In the case of compound measurements, they don't even do that much:

irb(main):005:0> 2.meters.per.second.to_s
=> "#<Alchemist::CompoundMeasurement:0x007ff3c18e9060>"
irb(main):006:0>

It'd be awesome if it printed nice strings for these:

=> 1.meter.to_s
"1 meter"
=> 3.seconds.to_s
"3 seconds"
=> 1.s.to_s
"1 second"
=> 30.miles.per.hour
"30 miles/hour"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.