humanize_fraction 0.1.0 → 0.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0beddb356fa1d63e5658dd2e25fb4916414fbd0
4
- data.tar.gz: 520506910e547967f3f5f485c51c8d8bb75fe6eb
3
+ metadata.gz: 71e2420b7a27230601ab8ae89e38f3097908f13f
4
+ data.tar.gz: 80455bea8b7ae37f41a686570ced33c3ffa78914
5
5
  SHA512:
6
- metadata.gz: 07e78cdf965891de22a42f8b92b41e366ac6f18dd58dccadd8783b8ec46b9b2114a1d1cb9fd68429c526d711eebd74f58232ba45ab2f8cbde533c4cc48c79198
7
- data.tar.gz: 8b4c46ebc18c7ae1f57c26a748c7599769fb82c05336c8bd553667cd6d4c16a8a5dd236fa8aac23a021ead71d4f1a790c58fc7ac773e4cce4de9f7979f58cda9
6
+ metadata.gz: 47ecefd1c758ef9de3c81505d16f6312ff3d339f42929feb7c5f4a992c4056ff430d05c30f599b7b85bc784a9bab666fd75250306ee77d624f75c71b119bf942
7
+ data.tar.gz: 8a3d6b9e0fd2337dadbf331ad8d17f386d46adc450ca0c4bee112810e458b2acc497fce5cbc300dc47a2b7d4fe50cce8166979283b065bcf218a073aab5ae9da
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # humanize_fraction [![CircleCI](https://circleci.com/gh/6/humanize_fraction.svg?style=svg)](https://circleci.com/gh/6/humanize_fraction)
1
+ # humanize_fraction [![CircleCI](https://circleci.com/gh/6/humanize_fraction.svg?style=svg)](https://circleci.com/gh/6/humanize_fraction) [![Gem Version](https://badge.fury.io/rb/humanize_fraction.svg)](https://rubygems.org/gems/humanize_fraction)
2
2
 
3
3
  Rubygem to convert fraction to words, like 1 ⅓ => one and a third. Examples:
4
4
 
@@ -15,6 +15,28 @@ Rubygem to convert fraction to words, like 1 ⅓ => one and a third. Examples:
15
15
  #=> "a millionth"
16
16
  "222/333".humanize_fraction
17
17
  #=> "two hundred and twenty-two three hundred thirty-thirds"
18
+ "1/1000000000000000000000000000".humanize_fraction(shorthand: true)
19
+ #=> "an octillionth"
20
+ ```
21
+
22
+ If you don't want to monkey patch `String`, you can also use the Humanizer class directly:
23
+
24
+ ```ruby
25
+ # From a string:
26
+ fraction = HumanizeFraction::Humanizer.from_string("2 1/4")
27
+
28
+ # From integers:
29
+ fraction = HumanizeFraction::Humanizer.new(
30
+ whole_part: 2,
31
+ numerator: 1,
32
+ denominator: 4,
33
+ )
34
+
35
+ fraction.to_s
36
+ # => "two and one fourth"
37
+
38
+ fraction.to_s(shorthand: true, quarter: true)
39
+ # => "two and a quarter"
18
40
  ```
19
41
 
20
42
  ## Installation
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_runtime_dependency "activesupport", ">= 4"
26
26
  spec.add_runtime_dependency "humanize", "~> 1.4"
27
- spec.add_runtime_dependency "twitter_cldr", "~> 4.4"
27
+ spec.add_runtime_dependency "numbers_and_words", "~> 0.11"
28
28
 
29
29
  spec.add_development_dependency "bundler", "~> 1.14"
30
30
  spec.add_development_dependency "rake", "~> 10.0"
@@ -2,7 +2,7 @@ module CoreExtensions
2
2
  module String
3
3
  module HumanizeFraction
4
4
  def humanize_fraction(options = {})
5
- ::HumanizeFraction::Humanizer.from_string(self, options).to_s
5
+ ::HumanizeFraction::Humanizer.from_string(self).to_s(options)
6
6
  end
7
7
  end
8
8
  end
@@ -1,34 +1,37 @@
1
1
  module HumanizeFraction
2
2
  class Humanizer
3
3
  # From: https://github.com/thechrisoshow/fractional/blob/master/lib/fractional.rb
4
- SINGLE_FRACTION = /^\s*(\-?\d+)\/(\-?\d+)\s*$/
5
- MIXED_FRACTION = /^\s*(\-?\d*)\s+(\d+)\/(\d+)\s*$/
4
+ SINGLE_FRACTION = /\A\s*(\-?\d+)\/(\-?\d+)\s*\z/
5
+ MIXED_FRACTION = /\A\s*(\-?\d*)\s+(\d+)\/(\d+)\s*\z/
6
6
 
7
- attr_reader :numerator, :denominator, :integer_part, :quarter, :shorthand
7
+ # Numbers that should be prefixed with `a` instead of `an` even though they
8
+ # start with a vowel.
9
+ NUMBERS_STARTING_WITH_SILENT_VOWEL = [
10
+ "one",
11
+ ]
8
12
 
9
- def initialize(numerator:, denominator:, integer_part: nil, shorthand: false, quarter: false)
13
+ attr_reader :numerator, :denominator, :whole_part
14
+
15
+ def initialize(numerator:, denominator:, whole_part: nil)
10
16
  [numerator, denominator].each do |number|
11
17
  if !number.is_a?(Integer)
12
18
  raise ArgumentError, "Expected Integers for numerator/denominator but got #{number.class.name}"
13
19
  end
14
20
  end
15
- if !integer_part.nil? && !integer_part.is_a?(Integer)
16
- raise ArgumentError, "Expected Integer or NilClass for integer_part but got #{integer_part.class.name}"
21
+ if !whole_part.nil? && !whole_part.is_a?(Integer)
22
+ raise ArgumentError, "Expected Integer or NilClass for whole_part but got #{whole_part.class.name}"
17
23
  end
18
- @integer_part = integer_part
24
+ @whole_part = whole_part
19
25
  @numerator = numerator
20
26
  @denominator = denominator
21
- @shorthand = shorthand
22
- @quarter = quarter
23
27
  end
24
- alias_method :quarter?, :quarter
25
- alias_method :shorthand?, :shorthand
26
28
 
27
- def to_s
29
+ def to_s(shorthand: false, quarter: false)
30
+ humanized_denominator = humanize_denominator(shorthand: shorthand, quarter: quarter)
28
31
  words = []
29
- words << humanize_integer_part if !integer_part.nil?
30
- words << humanize_numerator
31
- words << humanize_denominator
32
+ words << humanize_whole_part if !whole_part.nil?
33
+ words << humanize_numerator(humanized_denominator, shorthand: shorthand)
34
+ words << humanized_denominator
32
35
  words.join(" ")
33
36
  end
34
37
 
@@ -38,7 +41,7 @@ module HumanizeFraction
38
41
  end
39
42
  if string_is_mixed_fraction?(string)
40
43
  whole, numerator, denominator = string.scan(MIXED_FRACTION).flatten.map(&:to_i)
41
- new(integer_part: whole, numerator: numerator, denominator: denominator, **options)
44
+ new(whole_part: whole, numerator: numerator, denominator: denominator, **options)
42
45
  elsif string_is_single_fraction?(string)
43
46
  numerator, denominator = string.split("/").map(&:to_i)
44
47
  new(numerator: numerator, denominator: denominator, **options)
@@ -49,32 +52,31 @@ module HumanizeFraction
49
52
 
50
53
  private
51
54
 
52
- def humanize_integer_part
53
- "#{integer_part.humanize} and"
55
+ def humanize_whole_part
56
+ "#{whole_part.humanize} and"
54
57
  end
55
58
 
56
- def humanize_numerator
57
- number = if numerator == 1 && shorthand?
58
- # 8 is the only(?) case where you want to prefix with `an` instead of `a`.
59
- first_digit(denominator) == 8 ? "an" : "a"
59
+ def humanize_numerator(humanized_denominator, shorthand:)
60
+ number = if numerator == 1 && shorthand
61
+ first_number = humanized_denominator.split(" ").first
62
+ indefinite_article(first_number)
60
63
  else
61
64
  numerator.humanize
62
65
  end
63
66
  number
64
67
  end
65
68
 
66
- def humanize_denominator
69
+ def humanize_denominator(shorthand:, quarter:)
67
70
  number = case denominator
68
71
  when 2
69
72
  "half"
70
73
  when 4
71
- quarter? ? "quarter" : "fourth"
74
+ quarter ? "quarter" : "fourth"
72
75
  else
73
- denominator.localize(:en).to_rbnf_s("SpelloutRules", "spellout-ordinal")
76
+ I18n.with_locale(:en) { denominator.to_words(ordinal: true) }
74
77
  end
75
78
  # Handle case of `a millionth`, `a thousandth`, etc.
76
- if shorthand? && denominator >= 100 &&
77
- first_digit(denominator) == 1 && remaining_digits_zeros?(denominator)
79
+ if shorthand && denominator >= 100 && one_followed_by_zeros?(denominator)
78
80
  number.sub!(/\Aone\s/, "")
79
81
  end
80
82
  if numerator != 1
@@ -83,15 +85,20 @@ module HumanizeFraction
83
85
  number
84
86
  end
85
87
 
86
- def first_digit(number)
87
- number.to_s.split("").first.to_i
88
+ # Checks number is a 1 followed by only zeros, e.g. 10 or 10000000
89
+ def one_followed_by_zeros?(number)
90
+ digits = number.to_s.split("")
91
+ first_digit = digits.shift
92
+ first_digit.to_i == 1 && digits.size > 0 && digits.map(&:to_i).all?(&:zero?)
88
93
  end
89
94
 
90
- # Checks if everything after first digit are zeros.
91
- def remaining_digits_zeros?(number)
92
- numbers = number.to_s.split("")
93
- numbers.shift
94
- numbers.size > 0 && numbers.map(&:to_i).all?(&:zero?)
95
+ def indefinite_article(humanized_number)
96
+ if humanized_number.match(/\A[aeiou]/) &&
97
+ !NUMBERS_STARTING_WITH_SILENT_VOWEL.include?(humanized_number)
98
+ "an"
99
+ else
100
+ "a"
101
+ end
95
102
  end
96
103
 
97
104
  def self.string_is_mixed_fraction?(value)
@@ -1,3 +1,3 @@
1
1
  module HumanizeFraction
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,6 +1,7 @@
1
1
  require "active_support/inflector"
2
2
  require "humanize"
3
- require "twitter_cldr"
3
+ # TODO: figure out how to use this library without the monkey patching it does.
4
+ require "numbers_and_words"
4
5
 
5
6
  require "humanize_fraction/humanizer"
6
7
  require "humanize_fraction/version"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: humanize_fraction
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Graham
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.4'
41
41
  - !ruby/object:Gem::Dependency
42
- name: twitter_cldr
42
+ name: numbers_and_words
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.4'
47
+ version: '0.11'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.4'
54
+ version: '0.11'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement