Code Monkey home page Code Monkey logo

number's Introduction

Number

Build Status Inline docs Coverage Status Module Version Hex Docs Total Download License Last Updated

Number is an Elixir library which provides functions to convert numbers into a variety of different formats. Ultimately, it aims to be a partial clone of ActionView::Helpers::NumberHelper from Rails.

Number.Currency.number_to_currency(2034.46)
"$2,034.46"

Number.Phone.number_to_phone(1112223333, area_code: true, country_code: 1)
"+1 (111) 222-3333"

Number.Percentage.number_to_percentage(100, precision: 0)
"100%"

Number.Human.number_to_human(1234)
"1.23 Thousand"

Number.Delimit.number_to_delimited(12345678)
"12,345,678"

Installation

Get it from Hex:

defp deps do
  [{:number, "~> 1.0.1"}]
end

Then run mix deps.get.

Usage

If you want to import all of the functions provided by Number, simply use it in your module:

defmodule MyModule do
  use Number
end

More likely, you'll want to import the functions you want from one of Number's submodules.

defmodule MyModule do
  import Number.Currency
end

See the Hex documentation for more information about the modules provided by Number.

License

MIT. See LICENSE for more details.

number's People

Contributors

akash-akya avatar alexfilatov avatar bkilshaw avatar bratsche avatar danielberkompas avatar eptis avatar fiodorbaczynski avatar jclem avatar kerryjj avatar kianmeng avatar lleger avatar lowks avatar michalmuskala avatar nmbrone avatar sergiotapia avatar stereosteve avatar stuartbain avatar superhawk610 avatar unti1x 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

number's Issues

Add an option to number_to_human for short labels

The labels are currently hardcoded to Thousand, Million, Billion, Trillion, or Quadrillion. It would be nice to be able to pass a list of these yourself as one of the options, similar to how millify does it. For example:

iex> Number.Human.number_to_human(1440000, units: ["B", "KB", "MB", "GB", "TB"])
1.44 MB

Add to application list in mix.exs?

The readme indicates that we need to "Make sure you also add it to your application list in mix.exs". Is this information correct, because it doesn't look like that number is an OTP application?

Potential precision loss formatting decimals, integers, and strings

These issues all stem from the different formatters converting the value to a float before formatting it. I'm not sure if this is something you want the library to handle however. If you did want to alleviate the problem converting everything to Decimal and changing the functions to use that instead would be the easiest solution (though would mean Decimal would need to be a required dependency). If you don't want Decimal as a required dependency, then the other way to solve it would probably be to introduce a new conversion type that respects precision (a string or some format based on integers) and then operating on that.

Changelog entry for 1.0.0

πŸ‘‹ Hi Daniel!

Thanks for maintaining this library. I recently had to do an upgrade from 0.5.7 to 1.0.0, and noticed there wasn't a changelog entry specifically for 1.0.0 -- just "unreleased" -- so I wasn't super clear on what was unreleased vs in 1.0.0. It would be useful to have a specific entry in the CHANGELOG for it now that it's published.

Thanks!

Cannot parse number without affecting precision

Issue Title

Cannot parse number without affecting precision

Description

When attempting to delimit a number, it's currently required to specify precision (or the default precision of 2 is used). The goal is to parse a string without affecting the precision of the number.

Example

For instance, given the number 203344.43224455333 and using options [precision: :inf, separator: ".", delimiter: ","], the expected result is:
"203,344.43224455333".

Summary

The function should offer the capability to set a "inf" precision, which means that in such cases, precision should remain unaffected.

Negative Decimal problem

iex(15)> Number.Currency.number_to_currency(Decimal.new(-100.01))
"$100.01"

Looks like the number < 0 guard clauses don't work with Decimal because:

iex(16)> Decimal.new(-100.01) < 0
false

number_to_human skips some numbers

iex(6)> Number.Human.number_to_human 998994
"998.99 Thousand"
iex(7)> Number.Human.number_to_human 998999
"998.00 Thousand"
iex(8)> Number.Human.number_to_human 999000
"999.00 Thousand"
iex(9)> Number.Human.number_to_human 999001
** (FunctionClauseError) no function clause matching in Number.Human.number_to_human/2
    lib/number/human.ex:47: Number.Human.number_to_human(999001, [])
  1. The result for 998999 should be "998.99 thousand" not "999.00 thousand"? It looks like it's rounding the decimal portion (0.999) up (to 1.000) and then just using the .000 part (since 998,994 works correctly but 998,995-998,999 do not)?
  2. 999,001 through 999,999 raise an error. Same with 999,000,001 through 999,999,999, etc. This is because the multiplier of 999 gives a max of 999,000 for 1,000, 999,000,000 for 1,000,000, etc.

I can look into this and possibly provide a pull request when I have some more time.

Number formatting with abbreviations: $1,200,000 -> $1.2MM, $5,586 -> $5.6k, etc.

I'm just wondering if it's possible to use this package to round/convert to "business-y" numbers. I'd like to display larger values, often currency, and use the abbreviated forms.

I can easily round on my own (ie. 5586 -> 5.6 x 1000), but it would be great if there were a way to then get the abbreviation suffix (ie. "MM", "k", "B"?) I guess once I list them out, there's only those 3 (and therefore not that hard), but I'm still wondering if there's anything built-in.

Broken behavior with Decimal version 1.x

In Decimal 2.0 there is a breaking change in how compare works - now it returns :gt | :eq | :lt. Previously it returned #Decimal<-1>, #Decimal<0> or #Decimal<1>.

The 1.0.2 version of Number can work both with ~> 1.5 and ~> 2.0 versions of Decimal. When working with ~> 1.5 versions, there are checks that can never match, leading to wrong behaviour. For example in Number.Human.number_to_human/{1,2} we see the following code:

cond do
      compare(number, ~d(999)) == :gt && compare(number, ~d(1_000_000)) == :lt ->
        delimit(number, ~d(1_000), "Thousand", options)
...

The result of this compare would be a decimal and not an atom, so the function will always execute the last clause:

true ->
        number_to_delimited(number, options)

Example:

iex(1)> :application.get_key(:number, :vsn)
{:ok, '1.0.2'}
iex(2)> Number.Human.number_to_human(1_234_456_789_000_000)
"1,234,456,789,000,000.00"

Deprecation warnings in Elixir 1.5

warning: String.rstrip/2 is deprecated, use String.trim_trailing/2 with a binary as second argument
  lib/number/si.ex:117

warning: String.rstrip/2 is deprecated, use String.trim_trailing/2 with a binary as second argument
  lib/number/si.ex:117

warning: Integer.to_char_list/1 is deprecated, use Integer.to_charlist/1
  lib/number/delimit.ex:133

Rounding fails

While having different issues, I ran the provided tests and one failed:

$ mix test
................

  1) test SI.number_to_si (Number.SITest)
     test/number/si_test.exs:7
     Assertion with == failed
     code:  assert SI.number_to_si(2.3456e9, base: 1024, unit: "B") == "2.19GB"
     left:  "2.18GB"
     right: "2.19GB"
     stacktrace:
       test/number/si_test.exs:56: (test)

...............................................................

Finished in 0.1 seconds
72 doctests, 8 tests, 1 failure

Randomized with seed 339261

Just wanted to report it…

Erlang/OTP 21 [erts-10.1.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe] [dtrace]

Elixir 1.7.4 (compiled with Erlang/OTP 21)

Decimal.compare is deprecated

warning: Decimal.compare/2 is deprecated. Use Decimal.cmp/2 instead. This function will be re-introduced in Decimal v2.0 with new return value
lib/number/decimal.ex:11: Number.Decimal.compare/2

You can just replace it with Decimal.cmp/2

Let me know if anything doesn't make sense

If you use application config this library breaks in mix release on 1.9

I think it would be worth removing the ability to configure through Application config, as it should be discouraged (that's not what application config is for) and it currently wont work if you use mix releases in 1.9 because of this bug: elixir-lang/elixir#9225

I'd be happy to make a PR, would have to be a major update though, as it will be breaking for people who are using application config.

Error in hex doc

In the doc for delimit module, there is a demo config which use "delimiter" as key for the config of the module, where it should be "delimit"

number_to_delimited shows 2 decimal places. Readme says otherwise.

The readme on this repo has the following as one of the examples

Number.Delimit.number_to_delimited(12345678)
"12,345,678"

However, when I run that exact command in iex I get

Number.Delimit.number_to_delimited(12345678)
"12,345,678.00"

Should there be a discrepancy?

Invalid typespecs

I've been using ElixirLS lately, so I've been noticing typespec errors more frequently. I ran dialyzer against this project, because I wasn't entirely sure if my project was doing something wrong, or if there were invalid typespecs in this package.

This is the dialyzer output I got with Erlang 20.0.5 and Elixir 1.6.0.

:0: Unknown function 'Elixir.Number.Conversion.Atom':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.Function':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.List':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.Map':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.PID':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.Port':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.Reference':'__impl__'/1
:0: Unknown function 'Elixir.Number.Conversion.Tuple':'__impl__'/1
lib/number/currency.ex:92: Invalid type specification for function 'Elixir.Number.Currency':number_to_currency/2. The success typing is ('nil',_) -> 'nil'
lib/number/currency.ex:98: The call 'Elixir.Number.Delimit':number_to_delimited(Vnumber@2::#{'__struct__':='Elixir.Decimal', 'coef':='inf' | 'qNaN' | 'sNaN' | non_neg_integer(), 'exp':=integer(), 'sign':=-1 | 1},Voptions@2::[{atom(),_}]) breaks the contract (number(),[any()]) -> 'Elixir.String':t()
lib/number/human.ex:69: The call 'Elixir.Number.Delimit':number_to_delimited(Vnumber@1::#{'__struct__':='Elixir.Decimal', 'coef':='inf' | 'qNaN' | 'sNaN' | non_neg_integer(), 'exp':=integer(), 'sign':=-1 | 1},Voptions@1::any()) breaks the contract (number(),[any()]) -> 'Elixir.String':t()
lib/number/human.ex:112: Function delimit/4 has no local return
lib/number/human.ex:116: The call 'Elixir.Number.Delimit':number_to_delimited(#{'__struct__':='Elixir.Decimal', 'coef':='inf' | 'qNaN' | 'sNaN' | non_neg_integer(), 'exp':=integer(), 'sign':=-1 | 1},Voptions@1::any()) breaks the contract (number(),[any()]) -> 'Elixir.String':t()
done (warnings were emitted)

In my project, I came across the error regarding decimals simply by passing a Decimal to number_to_currency.

Number.Conversion is not used internally

I am trying to use this package in combination with Ecto.

The numbers I have are saved in the Decimal format that is used by Ecto. When attempting to pass these to Number, an error is thrown, as this format is not recognized.

I attempted to implement the Number.Conversion protocol for this data type, but it turns out that this is not actually used for Number.Currency.number_to_currency.

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.