rafini 1.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
- SHA1:
3
- metadata.gz: bcf2292d9da70068c6595c31195265cacea43c9d
4
- data.tar.gz: 9dcab18064c2eeb25340182f22e26632141f82f0
2
+ SHA256:
3
+ metadata.gz: df4dc73d0b92dcd762d1c741eb30f8dcfc56fdd84d18bfdbc2435290d9a3df97
4
+ data.tar.gz: c7764c8ae13bb99ff51977d7b52f926eee9083e5db6f75e43c860c2eb9557715
5
5
  SHA512:
6
- metadata.gz: 404b14d5065305fa3c792bb6f3b43af65f292e99d3a2b50c89db45fa2fa16bf9e8468af4f5c65e95de6e401a21c3d46a06d752e93e8b97d85c0ec81f6267739d
7
- data.tar.gz: c41acda381c48132bee1dd21115db290059387f04d7c1b4ce914f2b780fc7de679a302d23a9c75a02e905f6856d4aba146d80cc9edc8e1465f54215c1ae95105
6
+ metadata.gz: eb0f6fcdf17d108b75ddd5af587ceb7fe2d6294e8134cfeae90807f62607d49e158754903526f49b22fb6522a4ded0cf2f1522ad9c1305f295b9bd858cad9714
7
+ data.tar.gz: 8b327f489cfa71d77eca28df39b4408fcf8c7c4c8e7ed233c10f05e242bcfee0936a96f97e5bb8eee0fa4f49a058bc7b754fc549ab47d8e70574e756ccdc1d93
@@ -0,0 +1,159 @@
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)
6
+
7
+ ## DESCRIPTION:
8
+
9
+ Just a collection of useful refinements.
10
+
11
+ ## INSTALL:
12
+
13
+ ```shell
14
+ $ gem install rafini
15
+ ```
16
+
17
+ ## SYNOPSIS:
18
+
19
+ ### using Rafini::Array
20
+
21
+ ```ruby
22
+ require 'rafini/array'
23
+ using Rafini::Array
24
+
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"
30
+
31
+ # is
32
+ [:a,:b,:c].is(true) #=> {:a=>true, :b=>true, :c=>true}
33
+ ```
34
+ ### Rafini::Empty
35
+
36
+ ```ruby
37
+ require 'rafini/empty'
38
+ include Rafini::Empty
39
+ s0 #=> ""
40
+ a0 #=> []
41
+ h0 #=> {}
42
+ [s0,a0,h0].all?(&:frozen?) #=> true
43
+ ```
44
+
45
+ ### using Rafini::Exception
46
+
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
+ ```
79
+
80
+ ### using Rafini::Hash
81
+
82
+ ```ruby
83
+ require 'rafini/hash'
84
+ using Rafini::Hash
85
+
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"
91
+
92
+ # supplement
93
+ {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {:a=>"A", :b=>"B", :c=>"C", :d=>"D"}
94
+
95
+ # amend
96
+ {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {:a=>"A", :b=>"X"}
97
+ ```
98
+
99
+ ### using Rafini::Integer
100
+
101
+ ```ruby
102
+ require 'rafini/integer'
103
+ using Rafini::Integer
104
+
105
+ # odometer
106
+ 123.odometer(10,10) #=> [3, 2, 1]
107
+ 30.odometer(2,3,5) #=> [0, 0, 0, 1]
108
+ ```
109
+
110
+ ### using Rafini::Odometers
111
+
112
+ ```ruby
113
+ require 'rafini/odometers'
114
+ using Rafini::Odometers
115
+
116
+ # sec2time
117
+ 12501.sec2time.to_s #=> "3 hours and 28 minutes"
118
+
119
+ # illion
120
+ 3_512_325.illion.to_s #=> "3.51M"
121
+ ```
122
+
123
+ ### using Rafini::String
124
+
125
+ ```ruby
126
+ require 'rafini/string'
127
+ using Rafini::String
128
+
129
+ # camelize
130
+ 'a_camel_kick'.camelize #=> "ACamelKick"
131
+
132
+ # semantic
133
+ '1.2.3'.semantic(0..1) #=> "1.2"
134
+ ```
135
+
136
+ ## LICENSE:
137
+
138
+ (The MIT License)
139
+
140
+ Copyright (c) 2021 carlosjhr64
141
+
142
+ Permission is hereby granted, free of charge, to any person obtaining
143
+ a copy of this software and associated documentation files (the
144
+ 'Software'), to deal in the Software without restriction, including
145
+ without limitation the rights to use, copy, modify, merge, publish,
146
+ distribute, sublicense, and/or sell copies of the Software, and to
147
+ permit persons to whom the Software is furnished to do so, subject to
148
+ the following conditions:
149
+
150
+ The above copyright notice and this permission notice shall be
151
+ included in all copies or substantial portions of the Software.
152
+
153
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
154
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
155
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
156
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
157
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
158
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
159
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,13 +1,12 @@
1
- require 'rafini/version'
2
-
3
- require 'rafini/array'
4
- require 'rafini/exception'
5
- require 'rafini/hash'
6
- require 'rafini/integer'
7
- require 'rafini/string'
8
-
9
- require 'rafini/odometers'
10
- require 'rafini/empty'
11
-
1
+ module Rafini
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
+ end
12
11
  # Requires:
13
12
  #`ruby`
@@ -1,59 +1,42 @@
1
1
  module Rafini
2
2
  module Array
3
3
  refine ::Array do
4
-
5
- # string = array.joins(sep1,sep2,sep3,...){|i| sep[i]}
4
+ # type _AToS = ::Array[(_AToS|_ToS)]
5
+ # _AToS#joins(*_AToS seps)?{(_ToS,_ToS)->_ToS}
6
6
  #
7
- # Returns a string created by converting each element of the array to
8
- # 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.
9
9
  # If no separators are given or are used up,
10
- # it uses the value of the executed block, which is passed an iteration number.
11
- # Note that the iteration number starts at 1.
12
- # Lastly it uses an empty string.
13
- # ['a','b','c','d','e','f'].joins('-', '-', ' '){':'} #=> 'a-b-c d:e:f'
14
- # ['a','b','c'].joins{','} #=> 'a,b,c'
15
- # ['1','2','3'].joins('.') #=> '1.23'
16
- # ['a','b','c'].joins{|i|i} #=> 'a1b2c'
17
- def joins(*p, &block)
18
- str = ''
19
- if length > 1
20
- str << self[0]
21
- 1.upto(length-1) do |i|
22
- str << (p.empty? ? (block ? block.call(i).to_s : '') : p.shift.to_s)
23
- str << self[i]
24
- 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
25
29
  end
26
- return str
27
- end
28
-
29
- # array1.per(array2){|obj1, obj2| ... }
30
- #
31
- # Gives the block each two elements of two array respectively.
32
- # If the second array is not given, it passes the block the index number instead.
33
- # h={} # say you have a hash h, then
34
- # ['a','b','c'].per(['A','B','C']){|l,n| h[l]=n} # h=={'a'=>'A','b'=>'B','c'=>'C'}
35
- # ['a','b','c'].per{|l,i| h[l]=i} # h=={'a'=>0,'b'=>1,'c'=>2}
36
- def per(b=nil)
37
- 0.upto(length-1){|i| yield self[i], (b)? b[i] : i}
38
- end
39
-
40
- # array.which{|a|...}
41
- #
42
- # Returns first object for which block is true.
43
- # ['dog','cat','bunny'].which{|a|a=~/c/} #=> "cat"
44
- def which
45
- self.each{|obj| return obj if yield(obj)}
46
- return nil
30
+ return string
47
31
  end
48
32
 
49
33
  # [:a,:b,:c].is(true) #=> {:a=>true,:b=>true,:c=>true}
50
34
  #
51
35
  # Updates a hash with the keys given by the array to the given value.
52
36
  def is(value, hash={})
53
- self.each{|key| hash[key]=value}
37
+ each{|key| hash[key]=value}
54
38
  return hash
55
39
  end
56
-
57
40
  end
58
41
  end
59
42
  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
@@ -1,7 +1,6 @@
1
1
  module Rafini
2
2
  module Exception
3
3
  refine ::Exception do
4
-
5
4
  # $!.puts outputs to standard error what went bang!
6
5
  # The given message is what you normally want to see.
7
6
  # The exeption message is also shown if in verbose mode.
@@ -1,33 +1,18 @@
1
1
  module Rafini
2
2
  module Hash
3
3
  refine ::Hash do
4
-
5
4
  # struct = hash.to_struct
6
5
  # Why not?
7
- def to_struct
8
- Struct.new(*self.keys).new(*self.values)
6
+ def to_struct(&blk)
7
+ Struct.new(*keys, &blk).new(*values)
9
8
  end
10
9
 
11
- # hash0.modify(hash1,...) #=> hash
12
- #
13
- # Updates hash with hashes.
14
- # Overwrites existing elements and adds elements.
15
- # {a:'A',b:'B'}.modify({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X',c:'Y',d:'D'}
16
- def modify(*hashes)
17
- hashes.each do |hash|
18
- hash.each do |key, value|
19
- self[key] = value
20
- end
21
- end
22
- self
23
- end
24
-
25
- # hash0.supplement(hash1,...) #=> hash
10
+ # hash0.supplement!(hash1,...) #=> hash
26
11
  #
27
12
  # Supplements hash with hashes.
28
13
  # Adds missing elements only.
29
14
  # {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'B',c:'C',d:'D'}
30
- def supplement(*hashes)
15
+ def supplement!(*hashes)
31
16
  hashes.each do |hash|
32
17
  hash.each do |key, value|
33
18
  self[key] = value unless self.has_key?(key)
@@ -35,24 +20,24 @@ module Rafini
35
20
  end
36
21
  self
37
22
  end
23
+ def supplement(...)
24
+ self.dup.supplement!(...)
25
+ end
38
26
 
39
- # hash0.ammend(hash1,...)
27
+ # hash0.amend(hash1,...)
40
28
  #
41
29
  # Ammends hash with hashes.
42
- # Overwrites existing elements only.
43
- # {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
44
- def amend(*hashes)
45
- self.keys.each do |key|
46
- hashes.each do |hash|
47
- if hash.has_key?(key)
48
- self[key] = hash[key]
49
- break
50
- end
51
- 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
52
35
  end
53
36
  self
54
37
  end
55
-
38
+ def amend(...)
39
+ self.dup.amend!(...)
40
+ end
56
41
  end
57
42
  end
58
43
  end
@@ -1,26 +1,28 @@
1
1
  module Rafini
2
2
  module Integer
3
3
  refine ::Integer do
4
-
5
4
  # odometer
6
5
  # Kinda hard to explain...
7
6
  # 123.odometer(10,10) #=> [3,2,1]
8
7
  # 30.odometer(2,3,5) #=> [0,0,0,1]
9
8
  # ((60*60*24)*3 + (60*60)*12 + 60*15 + 30).odometer(60,60,24) #=> [30, 15, 12, 3]
10
9
  # Useful for making clocks, number scales, mayan long count... etc.
11
- def odometer(*p)
12
- n = self
13
- m = p.inject(1,:*)
14
- r = []
10
+ def odometer(*levels, factors: true)
11
+ raise RangeError, 'negative odometer' if self < 0
12
+ readings, remainder = [], self
13
+
14
+ levels = levels.inject([1]){|m, f| m.push(m.last*f)} if factors
15
+ levels.shift
15
16
 
16
- (p.length-1).downto(0) do |i|
17
- y = n/m; r.unshift y
18
- n = n%m
19
- f = p[i]; m = m/f
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
20
22
  end
21
- r.unshift n
22
23
 
23
- return r
24
+ # in case of a float, round
25
+ readings.unshift remainder.round
24
26
  end
25
27
  end
26
28
  end
@@ -1,80 +1,103 @@
1
+ require 'rafini/integer'
2
+ require 'rafini/hash'
3
+
1
4
  module Rafini
2
5
  module Odometers
3
- refine ::Integer do
4
- # Need Rafini::Integer for #odometer
5
- # Need Rafini::Hash for #to_struct
6
- # Need Rafini::Array for #per
7
- [Rafini::Integer, Rafini::Hash, Rafini::Array].each{|mod| using mod}
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,
10
+ minute: 60,
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,
24
+ }
8
25
 
9
- def odoread(scale)
10
- values = scale.values
11
- keys = scale.keys;
12
- counts = self.odometer(*values[0..-2])
26
+ SCALE = { # levels
27
+ base: {
28
+ one: 1,
29
+ ten: 10,
30
+ hundred: 100,
31
+ thousand: 10**3,
32
+ million: 10**6,
33
+ },
34
+ short: {
35
+ billion: 10**9,
36
+ trillion: 10**12,
37
+ quadrillion: 10**15,
38
+ },
39
+ long: {
40
+ billion: 10**12,
41
+ trillion: 10**18,
42
+ quadrillion: 10**24,
43
+ },
44
+ }
13
45
 
14
- string = "#{counts[0]} #{keys[0]}#{(counts[0]==1)? '' : 's'}"
15
- (keys.length-1).downto(1) do |i|
16
- if counts[i] > 0
17
- string = "#{counts[i]} #{keys[i]}#{(counts[i]>1)? 's' : ''}"
18
- 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
19
53
  break
20
54
  end
55
+ next if count == 0
56
+ string << "#{count} #{key}#{s}"
21
57
  end
58
+ return string
59
+ end
60
+ end
22
61
 
23
- hash = {}
24
- keys.per(counts){|k,v| hash[k]=v}
25
- 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
26
65
 
27
- 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)
28
69
  end
29
70
 
30
- SEC2TIME = {
31
- second: 60,
32
- minute: 60,
33
- hour: 24,
34
- day: 7,
35
- week: 4,
36
- month: 13,
37
- year: 10,
38
- decade: 10,
39
- centurie: 10,
40
- millennium: 10,
41
- age: 10,
42
- epoch: 10,
43
- era: 5,
44
- eon: 2,
45
- gigaannum: nil,
46
- }
47
-
48
71
  # Integer#sec2time
49
72
  # Returns a struct with the different time scales for number of seconds.
50
- # Note that the month(4 weeks)/year(13 months) are not meant to be exact.
51
73
  # 10_000.sec2time.to_s #=> "2 hours and 46 minutes"
52
74
  # 10_000.sec2time.hour #=> 2
53
75
  def sec2time
54
- 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
55
99
  end
56
100
 
57
- SCALE = {
58
- base: {
59
- ones: 10,
60
- tens: 10,
61
- hundreds: 10,
62
- thousands: 1_000,
63
- },
64
- short: {
65
- millions: 1_000,
66
- billions: 1_000,
67
- trillions: 1_000,
68
- quadrillions: nil,
69
- },
70
- long: {
71
- millions: 1_000_000,
72
- billions: 1_000_000,
73
- trillions: 1_000_000,
74
- quadrillions: nil,
75
- },
76
- }
77
-
78
101
  # 1_230.illion.to_s #=> "1.23k"
79
102
  # 1_230_000.illion.to_s #=> "1.23M"
80
103
  # ...etc
@@ -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,8 +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
+ end
10
+
11
+ # semantic:
12
+ # 'a.b.c'.semantic(1) #=> 'b'
13
+ # 'a.b.c'.semantic(0..1) #=> 'a.b'
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)
9
18
  end
10
19
  end
11
20
  end
metadata CHANGED
@@ -1,24 +1,24 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rafini
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.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: 2014-12-25 00:00:00.000000000 Z
11
+ date: 2021-01-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: |
14
- Just a collection of useful refinements.
13
+ description: 'Just a collection of useful refinements.
14
+
15
+ '
15
16
  email: carlosjhr64@gmail.com
16
17
  executables: []
17
18
  extensions: []
18
- extra_rdoc_files:
19
- - README.rdoc
19
+ extra_rdoc_files: []
20
20
  files:
21
- - README.rdoc
21
+ - README.md
22
22
  - lib/rafini.rb
23
23
  - lib/rafini/array.rb
24
24
  - lib/rafini/empty.rb
@@ -27,15 +27,12 @@ files:
27
27
  - lib/rafini/integer.rb
28
28
  - lib/rafini/odometers.rb
29
29
  - lib/rafini/string.rb
30
- - lib/rafini/version.rb
31
30
  homepage: https://github.com/carlosjhr64/rafini
32
31
  licenses:
33
32
  - MIT
34
33
  metadata: {}
35
- post_install_message:
36
- rdoc_options:
37
- - "--main"
38
- - README.rdoc
34
+ post_install_message:
35
+ rdoc_options: []
39
36
  require_paths:
40
37
  - lib
41
38
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -49,11 +46,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
46
  - !ruby/object:Gem::Version
50
47
  version: '0'
51
48
  requirements:
52
- - 'ruby: ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-linux]'
53
- rubyforge_project:
54
- rubygems_version: 2.4.1
55
- 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:
56
52
  specification_version: 4
57
53
  summary: Just a collection of useful refinements.
58
54
  test_files: []
59
- has_rdoc:
@@ -1,114 +0,0 @@
1
- = rafini
2
-
3
- == DESCRIPTION:
4
-
5
- Just a collection of useful refinements.
6
-
7
- == SYNOPSIS:
8
-
9
- === using Rafini::Array
10
-
11
- # joins
12
- ['a','b','c','d','e','f'].joins('-','-',' '){':'} #=> "a-b-c d:e:f"
13
-
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'}
18
-
19
- # which
20
- ['dog','cat','bunny'].which{|a|a=~/c/} #=> "cat"
21
-
22
- # is
23
- [:a,:b,:c].is(true) #=> {a: true, b: true, c: true}
24
-
25
- # any?
26
- [:a,:b,:c].any?(:b,:d) #=> true
27
-
28
- === using Rafini::Exception
29
-
30
- # $!.puts
31
- begin
32
- raise 'Ugly Message'
33
- rescue RuntimeError
34
- $!.puts 'Nice Message'
35
- end
36
-
37
- # Rafini.bang!
38
- value = Rafini.bang!('Nice Message') do
39
- raise 'Ugly Message'
40
- end
41
- value #=> return value of block or error object
42
-
43
- # Rafini.thread_bang!
44
- Rafini.thread_bang!('Nice Message') do
45
- # this is in a thread
46
- raise 'Ugly Message'
47
- end
48
-
49
- === using Rafini::Hash
50
-
51
- # to_struc
52
- struct = {a:'A',b:'C',c:'C'}.to_struct
53
- struct.a #=> 'A'
54
-
55
- # modify
56
- {a:'A',b:'B'}.modify({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X',c:'Y',d:'D'}
57
-
58
- # supplement
59
- {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'B',c:'C',d:'D'}
60
-
61
- # amend
62
- {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
63
-
64
- === using Rafini::Integer
65
-
66
- # odometer
67
- 123.odometer(10,10) #=> [3,2,1]
68
- 30.odometer(2,3,5) #=> [0,0,0,1]
69
-
70
- === using Rafini::Odometers
71
-
72
- # sec2time
73
- 12501.sec2time.to_s #=> "3 hours and 28 minutes"
74
-
75
- # illion
76
- 3_512_325.illion.to_s #=> "3.51M"
77
-
78
- === using Rafini::String
79
-
80
- # camelize
81
- 'a_camel_kick'.camelize #=> "ACamelKick"
82
-
83
- === Rafini::Empty
84
-
85
- STRING, ARRAY, HASH = ''.frozen, [].frozen, {}.frozen
86
-
87
- == INSTALL:
88
-
89
- $ sudo gem install rafini
90
-
91
- == LICENSE:
92
-
93
- (The MIT License)
94
-
95
- Copyright (c) 2014 carlosjhr64
96
-
97
- Permission is hereby granted, free of charge, to any person obtaining
98
- a copy of this software and associated documentation files (the
99
- 'Software'), to deal in the Software without restriction, including
100
- without limitation the rights to use, copy, modify, merge, publish,
101
- distribute, sublicense, and/or sell copies of the Software, and to
102
- permit persons to whom the Software is furnished to do so, subject to
103
- the following conditions:
104
-
105
- The above copyright notice and this permission notice shall be
106
- included in all copies or substantial portions of the Software.
107
-
108
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
109
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
110
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
111
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
112
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
113
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
114
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,3 +0,0 @@
1
- module Rafini
2
- VERSION = '1.0.0'
3
- end