rafini 2.0.0 → 3.0.210112

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
  SHA256:
3
- metadata.gz: b81e63f8b4651660cd62560692546173a7ae971ce0a0a76b6bc772c573f2d181
4
- data.tar.gz: 37146803ff33ddcf74da2cd90bb5ddd4a2b1da0fe2be0c55b1b5b984a14029ca
3
+ metadata.gz: df4dc73d0b92dcd762d1c741eb30f8dcfc56fdd84d18bfdbc2435290d9a3df97
4
+ data.tar.gz: c7764c8ae13bb99ff51977d7b52f926eee9083e5db6f75e43c860c2eb9557715
5
5
  SHA512:
6
- metadata.gz: ecb3a3935d9892365a7568e304994605657b0ff0ed9c4e5adab0eee83c4d42d9584b0b6c6cdcd2d602f2817371d3a632f51396bf62b9ca134153c7eae926f22a
7
- data.tar.gz: a1795c03155fbaa64fd90b4a5a8ab4ad033fa5489bb925168a765ab4be71b742cca5bc61d282c88c9c4af75c2b9c24feb8c2bd87f5d01189a5b32e34fd2a8c89
6
+ metadata.gz: eb0f6fcdf17d108b75ddd5af587ceb7fe2d6294e8134cfeae90807f62607d49e158754903526f49b22fb6522a4ded0cf2f1522ad9c1305f295b9bd858cad9714
7
+ data.tar.gz: 8b327f489cfa71d77eca28df39b4408fcf8c7c4c8e7ed233c10f05e242bcfee0936a96f97e5bb8eee0fa4f49a058bc7b754fc549ab47d8e70574e756ccdc1d93
data/README.md CHANGED
@@ -1,101 +1,143 @@
1
- # rafini 2.0.0
1
+ # Rafini
2
+
3
+ * [VERSION 3.0.210112](https://github.com/carlosjhr64/rafini/releases)
4
+ * [github](https://github.com/carlosjhr64/rafini)
5
+ * [rubygems](https://rubygems.org/gems/rafini)
2
6
 
3
7
  ## DESCRIPTION:
4
8
 
5
9
  Just a collection of useful refinements.
6
10
 
11
+ ## INSTALL:
12
+
13
+ ```shell
14
+ $ gem install rafini
15
+ ```
16
+
7
17
  ## SYNOPSIS:
8
18
 
9
19
  ### using Rafini::Array
10
20
 
11
- # joins
12
- ['a','b','c','d','e','f'].joins('-','-',' '){':'} #=> "a-b-c d:e:f"
21
+ ```ruby
22
+ require 'rafini/array'
23
+ using Rafini::Array
13
24
 
14
- # per
15
- h={}
16
- ['a','b','c'].per(['A','B','C']){|l,u| h[l]=u}
17
- h #=> {'a'=>'A','b'=>'B','c'=>'C'}
25
+ # joins
26
+ ['Y','M','D','h','m','s'].joins('-','-',' '){':'}
27
+ #=> "Y-M-D h:m:s"
28
+ [1,9,2,8,3,7,4,6,5,5].joins{|a,b|a>b ? '>': a<b ? '<': '='}
29
+ #=> "1<9>2<8>3<7>4<6>5=5"
18
30
 
19
- # which
20
- ['dog','cat','bunny'].which{|a|a=~/c/} #=> "cat"
31
+ # is
32
+ [:a,:b,:c].is(true) #=> {:a=>true, :b=>true, :c=>true}
33
+ ```
34
+ ### Rafini::Empty
21
35
 
22
- # is
23
- [:a,:b,:c].is(true) #=> {a: true, b: true, c: true}
36
+ ```ruby
37
+ require 'rafini/empty'
38
+ include Rafini::Empty
39
+ s0 #=> ""
40
+ a0 #=> []
41
+ h0 #=> {}
42
+ [s0,a0,h0].all?(&:frozen?) #=> true
43
+ ```
24
44
 
25
45
  ### using Rafini::Exception
26
46
 
27
- # $!.puts
28
- begin
29
- raise 'Ugly Message'
30
- rescue RuntimeError
31
- $!.puts 'Nice Message'
32
- end
33
-
34
- # Rafini.bang!
35
- value = Rafini.bang!('Nice Message') do
36
- raise 'Ugly Message'
37
- end
38
- value #=> return value of block or error object
39
-
40
- # Rafini.thread_bang!
41
- Rafini.thread_bang!('Nice Message') do
42
- # this is in a thread
43
- raise 'Ugly Message'
44
- end
47
+ ```ruby
48
+ require 'rafini/exception'
49
+ using Rafini::Exception
50
+
51
+ # $!.puts
52
+ # Normally stderr.puts your "Nice" message.
53
+ # Additionally puts your "Ugly" message when $VERBOSE.
54
+ # Additionally puts backtrace when $DEBUG
55
+ # No output when $VERBOSE is nil.
56
+ begin
57
+ raise 'Ugly Message'
58
+ rescue RuntimeError
59
+ $!.puts 'Nice Message'
60
+ end
61
+
62
+ # Rafini.bang!
63
+ error = Rafini.bang!('Nice Message') do
64
+ raise 'Ugly Message'
65
+ # Outputs as $!.puts "Nice Message"
66
+ end
67
+ error.class #=> RuntimeError
68
+ error.to_s #=> "Ugly Message"
69
+
70
+ # Rafini.thread_bang!
71
+ thread = Rafini.thread_bang!('Nice Message') do
72
+ # this is in a thread
73
+ raise 'Ugly Message' # outputs as $!.puts 'Nice Message'
74
+ end
75
+ # The returned value joined from the thread
76
+ # will not re-raise the error(but gives the error).
77
+ thread.value.class #=> RuntimeError
78
+ ```
45
79
 
46
80
  ### using Rafini::Hash
47
81
 
48
- # to_struc
49
- struct = {a:'A',b:'C',c:'C'}.to_struct
50
- struct.a #=> 'A'
51
-
52
- # modify
53
- {a:'A',b:'B'}.modify({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X',c:'Y',d:'D'}
82
+ ```ruby
83
+ require 'rafini/hash'
84
+ using Rafini::Hash
54
85
 
55
- # supplement
56
- {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'B',c:'C',d:'D'}
86
+ # to_struc
87
+ struct = {a:'A',b:'C',c:'C'}.to_struct{ def ok = "OK" }
88
+ struct #=> #<struct a="A", b="C", c="C">
89
+ struct.a #=> "A"
90
+ struct.ok #=> "OK"
57
91
 
58
- # amend
59
- {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
92
+ # supplement
93
+ {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {:a=>"A", :b=>"B", :c=>"C", :d=>"D"}
60
94
 
61
- # maps
62
- {a:'A',b:'B',c:'C',c:'D'}.maps(:c,:a,:b) #=> ['C','A','B']
95
+ # amend
96
+ {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {:a=>"A", :b=>"X"}
97
+ ```
63
98
 
64
99
  ### using Rafini::Integer
65
100
 
66
- # odometer
67
- 123.odometer(10,10) #=> [3,2,1]
68
- 30.odometer(2,3,5) #=> [0,0,0,1]
101
+ ```ruby
102
+ require 'rafini/integer'
103
+ using Rafini::Integer
69
104
 
70
- ### using Rafini::Odometers
105
+ # odometer
106
+ 123.odometer(10,10) #=> [3, 2, 1]
107
+ 30.odometer(2,3,5) #=> [0, 0, 0, 1]
108
+ ```
71
109
 
72
- # sec2time
73
- 12501.sec2time.to_s #=> "3 hours and 28 minutes"
74
-
75
- # illion
76
- 3_512_325.illion.to_s #=> "3.51M"
110
+ ### using Rafini::Odometers
77
111
 
78
- ### using Rafini::String
112
+ ```ruby
113
+ require 'rafini/odometers'
114
+ using Rafini::Odometers
79
115
 
80
- # camelize
81
- 'a_camel_kick'.camelize #=> "ACamelKick"
116
+ # sec2time
117
+ 12501.sec2time.to_s #=> "3 hours and 28 minutes"
82
118
 
83
- # semantic
84
- '1.2.3'.semantic(0..1) #=> '1.2'
119
+ # illion
120
+ 3_512_325.illion.to_s #=> "3.51M"
121
+ ```
85
122
 
86
- ### Rafini::Empty
123
+ ### using Rafini::String
87
124
 
88
- STRING, ARRAY, HASH = ''.frozen, [].frozen, {}.frozen
125
+ ```ruby
126
+ require 'rafini/string'
127
+ using Rafini::String
89
128
 
90
- ## INSTALL:
129
+ # camelize
130
+ 'a_camel_kick'.camelize #=> "ACamelKick"
91
131
 
92
- $ gem install rafini
132
+ # semantic
133
+ '1.2.3'.semantic(0..1) #=> "1.2"
134
+ ```
93
135
 
94
136
  ## LICENSE:
95
137
 
96
138
  (The MIT License)
97
139
 
98
- Copyright (c) 2020 carlosjhr64
140
+ Copyright (c) 2021 carlosjhr64
99
141
 
100
142
  Permission is hereby granted, free of charge, to any person obtaining
101
143
  a copy of this software and associated documentation files (the
@@ -1,12 +1,12 @@
1
1
  module Rafini
2
- VERSION = '2.0.0'
3
- require 'rafini/array'
4
- require 'rafini/exception'
5
- require 'rafini/hash'
6
- require 'rafini/integer'
7
- require 'rafini/string'
8
- require 'rafini/odometers'
9
- require 'rafini/empty'
2
+ VERSION = '3.0.210112'
3
+ autoload :Array, 'rafini/array'
4
+ autoload :Exception, 'rafini/exception'
5
+ autoload :Hash, 'rafini/hash'
6
+ autoload :Integer, 'rafini/integer'
7
+ autoload :String, 'rafini/string'
8
+ autoload :Odometers, 'rafini/odometers'
9
+ autoload :Empty, 'rafini/empty'
10
10
  end
11
11
  # Requires:
12
12
  #`ruby`
@@ -1,52 +1,40 @@
1
1
  module Rafini
2
2
  module Array
3
3
  refine ::Array do
4
- # string = array.joins(sep1,sep2,sep3,...){|i| sep[i]}
4
+ # type _AToS = ::Array[(_AToS|_ToS)]
5
+ # _AToS#joins(*_AToS seps)?{(_ToS,_ToS)->_ToS}
5
6
  #
6
- # Returns a string created by converting each element of the array to
7
- # a string, separated by the given separators.
7
+ # Returns a string created by joining the elements of the (flatten) array,
8
+ # separated by the given (flatten) separators.
8
9
  # If no separators are given or are used up,
9
- # it uses the value of the executed block, which is passed an iteration number.
10
- # Note that the iteration number starts at 1.
11
- # Lastly it uses an empty string.
12
- # ['a','b','c','d','e','f'].joins('-', '-', ' '){':'} #=> 'a-b-c d:e:f'
13
- # ['a','b','c'].joins{','} #=> 'a,b,c'
14
- # ['1','2','3'].joins('.') #=> '1.23'
15
- # ['a','b','c'].joins{|i|i} #=> 'a1b2c'
16
- def joins(*p, &block)
17
- str = ''
18
- if length > 0
19
- str << self[0]
20
- 1.upto(length-1) do |i|
21
- str << (p.empty? ? (block ? block.call(i).to_s : '') : p.shift.to_s)
22
- str << self[i]
23
- end
10
+ # it uses the value of the executed block, which is passed the next neigboring iteration items.
11
+ # Else, it just joins the items.
12
+ # ['2021','Jan','09','07','29','05'].joins('-', '-', ' '){':'}
13
+ # #=> "2021-Jan-09 07:29:05"
14
+ # [:a,[1,2],:b].joins{','} #=> 'a,1,2,b'
15
+ # [3,1,4,1,5,9].joins('.') #=> '3.14159'
16
+ # [1,9,2,8,3,7,4,6,5,5].joins{|a,b|a>b ? '>': a<b ? '<': '='}
17
+ # #=> "1<9>2<8>3<7>4<6>5=5"
18
+ def joins(*seps, &block)
19
+ return '' if length < 1
20
+ items = flatten
21
+ previous = items.shift
22
+ string = ::String.new previous.to_s
23
+ return string if items.empty?
24
+ seps.flatten!
25
+ while item = items.shift
26
+ sep = seps.shift&.to_s || block&.call(previous,item).to_s and string << sep
27
+ string << item.to_s
28
+ previous = item
24
29
  end
25
- return str
30
+ return string
26
31
  end
27
32
 
28
- # array1.per(array2){|obj1, obj2| ... }
29
- #
30
- # Gives the block each two elements of two array respectively.
31
- # If the second array is not given, it passes the block the index number instead.
32
- # h={} # say you have a hash h, then
33
- # ['a','b','c'].per(['A','B','C']){|l,n| h[l]=n} # h=={'a'=>'A','b'=>'B','c'=>'C'}
34
- # ['a','b','c'].per{|l,i| h[l]=i} # h=={'a'=>0,'b'=>1,'c'=>2}
35
- def per(b=nil)
36
- 0.upto(length-1){|i| yield self[i], (b)? b[i] : i}
37
- end
38
-
39
- # array.which{|a|...}
40
- #
41
- # Returns first object for which block is true.
42
- # ['dog','cat','bunny'].which{|a|a=~/c/} #=> "cat"
43
- alias which detect
44
-
45
33
  # [:a,:b,:c].is(true) #=> {:a=>true,:b=>true,:c=>true}
46
34
  #
47
35
  # Updates a hash with the keys given by the array to the given value.
48
36
  def is(value, hash={})
49
- self.each{|key| hash[key]=value}
37
+ each{|key| hash[key]=value}
50
38
  return hash
51
39
  end
52
40
  end
@@ -1,10 +1,11 @@
1
1
  module Rafini
2
- # In a world where objects are allowed to represent infinities,
3
- # Rafini dares to introduce empty sets. But WHY!???
4
- # Ta-ta-TUM...
5
2
  module Empty
6
- ARRAY = [].freeze
7
- HASH = {}.freeze
3
+ ARRAY = [].freeze
4
+ HASH = {}.freeze
8
5
  STRING = ''.freeze
6
+
7
+ def a0 = ARRAY
8
+ def h0 = HASH
9
+ def s0 = STRING
9
10
  end
10
11
  end
@@ -3,30 +3,16 @@ module Rafini
3
3
  refine ::Hash do
4
4
  # struct = hash.to_struct
5
5
  # Why not?
6
- def to_struct
7
- Struct.new(*self.keys).new(*self.values)
6
+ def to_struct(&blk)
7
+ Struct.new(*keys, &blk).new(*values)
8
8
  end
9
9
 
10
- # hash0.modify(hash1,...) #=> hash
11
- #
12
- # Updates hash with hashes.
13
- # Overwrites existing elements and adds elements.
14
- # {a:'A',b:'B'}.modify({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X',c:'Y',d:'D'}
15
- def modify(*hashes)
16
- hashes.each do |hash|
17
- hash.each do |key, value|
18
- self[key] = value
19
- end
20
- end
21
- self
22
- end
23
-
24
- # hash0.supplement(hash1,...) #=> hash
10
+ # hash0.supplement!(hash1,...) #=> hash
25
11
  #
26
12
  # Supplements hash with hashes.
27
13
  # Adds missing elements only.
28
14
  # {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'B',c:'C',d:'D'}
29
- def supplement(*hashes)
15
+ def supplement!(*hashes)
30
16
  hashes.each do |hash|
31
17
  hash.each do |key, value|
32
18
  self[key] = value unless self.has_key?(key)
@@ -34,30 +20,23 @@ module Rafini
34
20
  end
35
21
  self
36
22
  end
23
+ def supplement(...)
24
+ self.dup.supplement!(...)
25
+ end
37
26
 
38
- # hash0.ammend(hash1,...)
27
+ # hash0.amend(hash1,...)
39
28
  #
40
29
  # Ammends hash with hashes.
41
- # Overwrites existing elements only.
42
- # {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
43
- def amend(*hashes)
44
- self.keys.each do |key|
45
- hashes.each do |hash|
46
- if hash.has_key?(key)
47
- self[key] = hash[key]
48
- break
49
- end
50
- end
30
+ # Overwrites existing keys only with first key value found in amending hashes.
31
+ # {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
32
+ def amend!(*hashes)
33
+ self.each_key do |key|
34
+ value=hashes.find{_1.has_key? key}&.fetch(key) and self[key]=value
51
35
  end
52
36
  self
53
37
  end
54
-
55
- # hash.maps(key1,...)
56
- #
57
- # Maps parameters list with hash.
58
- # {a:'A",b:'B',c:'C'}.maps(:c,:a,:b) #=> ['C','A','B']
59
- def maps(*keys)
60
- keys.map{|_|self[_]}
38
+ def amend(...)
39
+ self.dup.amend!(...)
61
40
  end
62
41
  end
63
42
  end
@@ -7,19 +7,22 @@ module Rafini
7
7
  # 30.odometer(2,3,5) #=> [0,0,0,1]
8
8
  # ((60*60*24)*3 + (60*60)*12 + 60*15 + 30).odometer(60,60,24) #=> [30, 15, 12, 3]
9
9
  # Useful for making clocks, number scales, mayan long count... etc.
10
- def odometer(*p)
11
- n = self
12
- m = p.inject(1,:*)
13
- r = []
10
+ def odometer(*levels, factors: true)
11
+ raise RangeError, 'negative odometer' if self < 0
12
+ readings, remainder = [], self
14
13
 
15
- (p.length-1).downto(0) do |i|
16
- y = n/m; r.unshift y
17
- n = n%m
18
- f = p[i]; m = m/f
14
+ levels = levels.inject([1]){|m, f| m.push(m.last*f)} if factors
15
+ levels.shift
16
+
17
+ levels.reverse_each do |level|
18
+ # in case of a float, floor
19
+ reading = (remainder/level).floor
20
+ readings.unshift reading
21
+ remainder = remainder%level
19
22
  end
20
- r.unshift n
21
23
 
22
- return r
24
+ # in case of a float, round
25
+ readings.unshift remainder.round
23
26
  end
24
27
  end
25
28
  end
@@ -1,78 +1,101 @@
1
+ require 'rafini/integer'
2
+ require 'rafini/hash'
3
+
1
4
  module Rafini
2
5
  module Odometers
3
- SEC2TIME = {
4
- second: 60,
6
+ # Sidereal Year: https://en.wikipedia.org/wiki/Year
7
+ year = 365*24*60*60 + 6*60*60 + 9*60 + 9.76
8
+ SEC2TIME = { # levels
9
+ second: 1,
5
10
  minute: 60,
6
- hour: 24,
7
- day: 7,
8
- week: 4,
9
- month: 13,
10
- year: 10,
11
- decade: 10,
12
- centurie: 10,
13
- millennium: 10,
14
- age: 10,
15
- epoch: 10,
16
- era: 5,
17
- eon: 2,
18
- gigaannum: nil,
11
+ hour: 60*60,
12
+ day: 24*60*60,
13
+ week: 7*24*60*60,
14
+ month: year/12.0,
15
+ year: year,
16
+ decade: 10*year,
17
+ centurie: 100*year,
18
+ millennium: 1_000*year,
19
+ age: 10_000*year,
20
+ epoch: 100_000*year,
21
+ era: 1_000_000*year,
22
+ eon: 5_000_000*year,
23
+ gigaannum: 10_000_000*year,
19
24
  }
20
25
 
21
- SCALE = {
26
+ SCALE = { # levels
22
27
  base: {
23
- ones: 10,
24
- tens: 10,
25
- hundreds: 10,
26
- thousands: 1_000,
28
+ one: 1,
29
+ ten: 10,
30
+ hundred: 100,
31
+ thousand: 10**3,
32
+ million: 10**6,
27
33
  },
28
34
  short: {
29
- millions: 1_000,
30
- billions: 1_000,
31
- trillions: 1_000,
32
- quadrillions: nil,
35
+ billion: 10**9,
36
+ trillion: 10**12,
37
+ quadrillion: 10**15,
33
38
  },
34
39
  long: {
35
- millions: 1_000_000,
36
- billions: 1_000_000,
37
- trillions: 1_000_000,
38
- quadrillions: nil,
40
+ billion: 10**12,
41
+ trillion: 10**18,
42
+ quadrillion: 10**24,
39
43
  },
40
44
  }
41
45
 
42
- refine ::Integer do
43
- # Need Rafini::Integer for #odometer
44
- # Need Rafini::Hash for #to_struct
45
- # Need Rafini::Array for #per
46
- [Rafini::Integer, Rafini::Hash, Rafini::Array].each{|mod| using mod}
47
-
48
- def odoread(scale)
49
- values = scale.values
50
- keys = scale.keys;
51
- counts = self.odometer(*values[0..-2])
52
-
53
- string = "#{counts[0]} #{keys[0]}#{(counts[0]==1)? '' : 's'}"
54
- (keys.length-1).downto(1) do |i|
55
- if counts[i] > 0
56
- string = "#{counts[i]} #{keys[i]}#{(counts[i]>1)? 's' : ''}"
57
- string << " and #{counts[i-1]} #{keys[i-1]}#{(counts[i-1]>1)? 's' : ''}" if counts[i-1]>0
46
+ refine ::Hash do
47
+ def description
48
+ string = ''
49
+ reverse_each do |key, count|
50
+ s = (count==1)? '' : 's'
51
+ unless string.empty?
52
+ string << " and #{count} #{key}#{s}" if count > 0
58
53
  break
59
54
  end
55
+ next if count == 0
56
+ string << "#{count} #{key}#{s}"
60
57
  end
58
+ return string
59
+ end
60
+ end
61
61
 
62
- hash = {}
63
- keys.per(counts){|k,v| hash[k]=v}
64
- hash[:to_s]=string
62
+ refine ::Integer do
63
+ using Rafini::Integer # Need Rafini::Integer for #odometer
64
+ using Rafini::Hash # Need Rafini::Hash for #to_struct
65
65
 
66
- return hash.to_struct
66
+ def odoread(scale, **kw, &blk)
67
+ counts = odometer(*scale.values, **kw)
68
+ ::Hash[scale.keys.zip(counts)].to_struct(&blk)
67
69
  end
68
70
 
69
71
  # Integer#sec2time
70
72
  # Returns a struct with the different time scales for number of seconds.
71
- # Note that the month(4 weeks)/year(13 months) are not meant to be exact.
72
73
  # 10_000.sec2time.to_s #=> "2 hours and 46 minutes"
73
74
  # 10_000.sec2time.hour #=> 2
74
75
  def sec2time
75
- self.odoread(SEC2TIME)
76
+ odoread(SEC2TIME, factors:false) do
77
+ def to_s
78
+ string = nil
79
+ SEC2TIME.keys.reverse_each do |key|
80
+ count=self[key]
81
+ if string
82
+ if count > 0
83
+ string << " and #{count} #{key}"
84
+ string << 's' if count > 1
85
+ end
86
+ break
87
+ end
88
+ next if count==0
89
+ string = "#{count} #{key}"
90
+ string << 's' if count > 1
91
+ end
92
+ string = "0 #{SEC2TIME.first[0]}s" unless string
93
+ string
94
+ end
95
+ def to_i
96
+ SEC2TIME.to_a.map{|k,v|v*self[k]}.sum.round
97
+ end
98
+ end
76
99
  end
77
100
 
78
101
  # 1_230.illion.to_s #=> "1.23k"
@@ -91,37 +114,42 @@ module Rafini
91
114
  # m.quadrillions #=> 888
92
115
  # m.to_s #=> "888Q" It rounds up 888.7!
93
116
  def illion(type=:short)
94
- keys = SCALE[:base].keys + SCALE[type].keys
95
- values = SCALE[:base].values + SCALE[type].values
96
- counts = self.odometer(*values[0..-2])
97
-
98
- string = nil
99
- if self < 1_000
100
- string = self.to_s
101
- elsif self < 1_000_000
102
- d = (self<10_000)? 2 : (self<100_000)? 1 : 0
103
- m = (self/1000.0).round(d)
104
- string = "#{m}k"
105
- else
106
- (keys.length-1).downto(4) do |i|
107
- next unless counts[i]>0
108
- n = counts[i]
109
- if n < 1_000
110
- d = (n<10)? 2 : (n<100)? 1 : 0
111
- n = (n + counts[i-1]/values[i-1].to_f).round(d)
112
- else
113
- n = n.illion
117
+ scale = SCALE[:base].merge SCALE[type]
118
+ struct = odoread(scale, factors:false) do
119
+ def scale=(scale)
120
+ @scale=scale
121
+ end
122
+ def type=(type)
123
+ @type=type
124
+ end
125
+ def to_s
126
+ number = to_i
127
+ return number.to_s if number < 1_000
128
+ if number < 1_000_000
129
+ precision = (number<10_000)? 2 : (number<100_000)? 1 : 0
130
+ return "#{(number/1000.0).round(precision)}K"
114
131
  end
115
- string = "#{n}#{keys[i][0].upcase}"
116
- break
132
+ keys = @scale.keys.reverse_each
133
+ loop do
134
+ key = keys.next
135
+ n = self[key]
136
+ next if n == 0
137
+ if n < 1_000
138
+ precision = (n<10)? 2 : (n<100)? 1 : 0
139
+ scale = @scale[key].to_f
140
+ f = (number/scale).round(precision)
141
+ return "#{f}#{key[0].upcase}"
142
+ end
143
+ return "#{n.illion}#{key[0].upcase}"
144
+ end
145
+ end
146
+ def to_i
147
+ @scale.to_a.map{|k,v|v*self[k]}.sum
117
148
  end
118
149
  end
119
-
120
- hash = {}
121
- keys.per(counts){|k,v| hash[k]=v}
122
- hash[:to_s] = string
123
-
124
- return hash.to_struct
150
+ struct.type = type
151
+ struct.scale = scale
152
+ return struct
125
153
  end
126
154
  end
127
155
  end
@@ -4,17 +4,17 @@ module Rafini
4
4
  # camelize:
5
5
  # 1) A camel kick, as in "I gotz camelized".
6
6
  # 2) "a_camel_kick" => "ACamelKick"
7
- def camelize(sep=/_/)
8
- self.split(sep).map{|word|word.capitalize }.join('')
7
+ def camelize(sep='_')
8
+ self.split(sep).map(&:capitalize).join
9
9
  end
10
10
 
11
11
  # semantic:
12
12
  # 'a.b.c'.semantic(1) #=> 'b'
13
13
  # 'a.b.c'.semantic(0..1) #=> 'a.b'
14
- # 'a.b.c'.semantic(0..2, '/') #=> 'b/c'
15
- # 'a/b/c'.semantic(0..2, '.', /\//) #=> 'a.b.c'
16
- def semantic(v,s='.',sx=/\./)
17
- [*self.split(sx)[v]].join(s)
14
+ # 'a.b.c'.semantic(0..2, join:'/') #=> 'b/c'
15
+ # 'a/b/c'.semantic(0..2, split:'/', join:'.') #=> 'a.b.c'
16
+ def semantic(v=(0..2), split:'.', join:'.')
17
+ [*self.split(split)[v]].join(join)
18
18
  end
19
19
  end
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rafini
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.210112
5
5
  platform: ruby
6
6
  authors:
7
7
  - carlosjhr64
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-15 00:00:00.000000000 Z
11
+ date: 2021-01-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Just a collection of useful refinements.
14
14
 
@@ -31,7 +31,7 @@ homepage: https://github.com/carlosjhr64/rafini
31
31
  licenses:
32
32
  - MIT
33
33
  metadata: {}
34
- post_install_message:
34
+ post_install_message:
35
35
  rdoc_options: []
36
36
  require_paths:
37
37
  - lib
@@ -46,9 +46,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  requirements:
49
- - 'ruby: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]'
50
- rubygems_version: 3.1.2
51
- signing_key:
49
+ - 'ruby: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]'
50
+ rubygems_version: 3.2.3
51
+ signing_key:
52
52
  specification_version: 4
53
53
  summary: Just a collection of useful refinements.
54
54
  test_files: []