rafini 2.0.0 → 3.1.221212

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b81e63f8b4651660cd62560692546173a7ae971ce0a0a76b6bc772c573f2d181
4
- data.tar.gz: 37146803ff33ddcf74da2cd90bb5ddd4a2b1da0fe2be0c55b1b5b984a14029ca
3
+ metadata.gz: 8daaac2f079c639abaa892b634f6400f1b0e75ffead282c4551dc8fb7fe45fda
4
+ data.tar.gz: a383dca85331bc2cf43e443fc909a9612044ea2c0f73a33a7bc9c568f2db0370
5
5
  SHA512:
6
- metadata.gz: ecb3a3935d9892365a7568e304994605657b0ff0ed9c4e5adab0eee83c4d42d9584b0b6c6cdcd2d602f2817371d3a632f51396bf62b9ca134153c7eae926f22a
7
- data.tar.gz: a1795c03155fbaa64fd90b4a5a8ab4ad033fa5489bb925168a765ab4be71b742cca5bc61d282c88c9c4af75c2b9c24feb8c2bd87f5d01189a5b32e34fd2a8c89
6
+ metadata.gz: b169dce8d8edd85971c8e62c433b3485a863fa8327e84430e253d660dbc0ca5a89c0106830ecedbfdb52103fd12bfb0193b07504dbc50b2812ced3a12096595c
7
+ data.tar.gz: c62702b40d3f826f4a63828e3122dada54376c8cd23f358b17a1c6650e6fc79bec2914f706c55d61c2ba0a087e88c2a848cdaec7410bda5b238d44b33f6b4f9d
data/README.md CHANGED
@@ -1,101 +1,139 @@
1
- # rafini 2.0.0
1
+ # Rafini
2
+
3
+ * [VERSION 3.1.221212](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
+ ```shell
13
+ $ gem install rafini
14
+ ```
7
15
  ## SYNOPSIS:
8
-
16
+ ```ruby
17
+ require 'rafini'
18
+ ```
19
+ ### include Rafini::Empty
20
+ ```ruby
21
+ include Rafini::Empty
22
+
23
+ s0 #=> ""
24
+ a0 #=> []
25
+ h0 #=> {}
26
+ [s0,a0,h0].all?(&:frozen?) #=> true
27
+ ```
9
28
  ### using Rafini::Array
29
+ ```ruby
30
+ using Rafini::Array
10
31
 
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}
32
+ # classify(like Set#classify)
33
+ [1, 2.0, 'Three', 4.0].classify #=> {Integer=>[1], Float=>[2.0, 4.0], String=>["Three"]}
24
34
 
25
- ### using Rafini::Exception
26
-
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
35
+ # is
36
+ [:a,:b,:c].is(true) #=> {:a=>true, :b=>true, :c=>true}
45
37
 
38
+ # joins
39
+ ['Y','M','D','h','m','s'].joins('-','-',' '){':'}
40
+ #=> "Y-M-D h:m:s"
41
+ [1,9,2,8,3,7,4,6,5,5].joins{|a,b|a>b ? '>': a<b ? '<': '='}
42
+ #=> "1<9>2<8>3<7>4<6>5=5"
43
+ ```
46
44
  ### using Rafini::Hash
45
+ ```ruby
46
+ using Rafini::Hash
47
47
 
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'}
48
+ # to_struc
49
+ struct = {a:'A',b:'C',c:'C'}.to_struct{ def ok = "OK" }
50
+ struct #=> #<struct a="A", b="C", c="C">
51
+ struct.a #=> "A"
52
+ struct.ok #=> "OK"
54
53
 
55
- # supplement
56
- {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'B',c:'C',d:'D'}
57
-
58
- # amend
59
- {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
60
-
61
- # maps
62
- {a:'A',b:'B',c:'C',c:'D'}.maps(:c,:a,:b) #=> ['C','A','B']
54
+ # supplement
55
+ {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {:a=>"A", :b=>"B", :c=>"C", :d=>"D"}
63
56
 
57
+ # amend
58
+ {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {:a=>"A", :b=>"X"}
59
+ ```
64
60
  ### using Rafini::Integer
61
+ ```ruby
62
+ using Rafini::Integer
65
63
 
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
-
64
+ # odometer
65
+ 123.odometer(10,10) #=> [3, 2, 1]
66
+ 30.odometer(2,3,5) #=> [0, 0, 0, 1]
67
+ ```
78
68
  ### using Rafini::String
69
+ ```ruby
70
+ using Rafini::String
79
71
 
80
- # camelize
81
- 'a_camel_kick'.camelize #=> "ACamelKick"
82
-
83
- # semantic
84
- '1.2.3'.semantic(0..1) #=> '1.2'
85
-
86
- ### Rafini::Empty
72
+ # camelize
73
+ 'a_camel_kick'.camelize #=> "ACamelKick"
87
74
 
88
- STRING, ARRAY, HASH = ''.frozen, [].frozen, {}.frozen
89
-
90
- ## INSTALL:
91
-
92
- $ gem install rafini
75
+ # semantic
76
+ '1.2.3'.semantic(0..1) #=> "1.2"
93
77
 
78
+ # shellescape(like Shellwords.escape)
79
+ 'Hello World!'.shellescape #=> "Hello\\ World\\!"
80
+ ```
81
+ ### using Rafini::Exception
82
+ ```ruby
83
+ using Rafini::Exception
84
+
85
+ # $!.puts
86
+ # Normally stderr.puts your "Nice" message.
87
+ # Additionally puts your "Ugly" message when $VERBOSE.
88
+ # Additionally puts backtrace when $DEBUG
89
+ # No output when $VERBOSE is nil.
90
+ begin
91
+ raise 'Ugly Message'
92
+ rescue RuntimeError
93
+ $!.puts 'Nice Message'
94
+ end
95
+
96
+ # Rafini.bang!
97
+ error = Rafini.bang!('Nice Message') do
98
+ raise 'Ugly Message'
99
+ # Outputs as $!.puts "Nice Message"
100
+ end
101
+ error.class #=> RuntimeError
102
+ error.to_s #=> "Ugly Message"
103
+
104
+ # Rafini.thread_bang!
105
+ thread = Rafini.thread_bang!('Nice Message') do
106
+ # this is in a thread
107
+ raise 'Ugly Message' # outputs as $!.puts 'Nice Message'
108
+ end
109
+ # The returned value joined from the thread
110
+ # will not re-raise the error(but gives the error).
111
+ thread.value.class #=> RuntimeError
112
+ ```
113
+ ### using Rafini::Odometers
114
+ ```ruby
115
+ using Rafini::Odometers
116
+
117
+ # sec2time
118
+ 12501.sec2time.to_s #=> "3 hours and 28 minutes"
119
+
120
+ # illion
121
+ 3_512_325.illion.to_s #=> "3.51M"
122
+ ```
123
+ ### using Rafini::Requires
124
+ ```ruby
125
+ using Rafini::Requires
126
+
127
+ requires'
128
+ ruby ~>3.0
129
+ rafini ~>3.1
130
+ json ~>2.0' #=> ["json"]
131
+ ```
94
132
  ## LICENSE:
95
133
 
96
134
  (The MIT License)
97
135
 
98
- Copyright (c) 2020 carlosjhr64
136
+ Copyright (c) 2022 CarlosJHR64
99
137
 
100
138
  Permission is hereby granted, free of charge, to any person obtaining
101
139
  a copy of this software and associated documentation files (the
data/lib/rafini/array.rb CHANGED
@@ -1,54 +1,55 @@
1
1
  module Rafini
2
2
  module Array
3
3
  refine ::Array do
4
- # string = array.joins(sep1,sep2,sep3,...){|i| sep[i]}
5
- #
6
- # Returns a string created by converting each element of the array to
7
- # a string, separated by the given separators.
8
- # 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
24
- end
25
- return str
26
- end
27
-
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}
4
+ # classify:
5
+ # Like Set#classify
6
+ def classify(hash: ::Hash.new{|h,k|h[k]=[]}, &block)
7
+ block ||= lambda{|v|v.class}
8
+ self.each{|v| hash[block[v]] << v}
9
+ return hash
37
10
  end
38
11
 
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
-
12
+ # is:
45
13
  # [:a,:b,:c].is(true) #=> {:a=>true,:b=>true,:c=>true}
46
14
  #
47
15
  # Updates a hash with the keys given by the array to the given value.
48
16
  def is(value, hash={})
49
- self.each{|key| hash[key]=value}
17
+ each{|key| hash[key]=value}
50
18
  return hash
51
19
  end
20
+
21
+ # joins:
22
+ # type _AToS = ::Array[(_AToS|_ToS)]
23
+ # _AToS#joins(*_AToS seps)?{(_ToS,_ToS)->_ToS}
24
+ #
25
+ # Returns a string created by joining the elements of the (flatten) array,
26
+ # separated by the given (flatten) separators.
27
+ # If no separators are given or are used up,
28
+ # it uses the value of the executed block,
29
+ # which is passed the next neigboring iteration items.
30
+ # Else, it just joins the items.
31
+ # ['2021','Jan','09','07','29','05'].joins('-', '-', ' '){':'}
32
+ # #=> "2021-Jan-09 07:29:05"
33
+ # [:a,[1,2],:b].joins{','} #=> 'a,1,2,b'
34
+ # [3,1,4,1,5,9].joins('.') #=> '3.14159'
35
+ # [1,9,2,8,3,7,4,6,5,5].joins{|a,b|a>b ? '>': a<b ? '<': '='}
36
+ # #=> "1<9>2<8>3<7>4<6>5=5"
37
+ def joins(*seps, &block)
38
+ return '' if length < 1
39
+ items = flatten
40
+ previous = items.shift
41
+ string = ::String.new previous.to_s
42
+ return string if items.empty?
43
+ seps.flatten!
44
+ while item = items.shift
45
+ if sep = seps.shift&.to_s || block&.call(previous,item)&.to_s
46
+ string << sep
47
+ end
48
+ string << item.to_s
49
+ previous = item
50
+ end
51
+ return string
52
+ end
52
53
  end
53
54
  end
54
55
  end
data/lib/rafini/empty.rb CHANGED
@@ -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
@@ -29,7 +29,7 @@ using Rafini::Exception
29
29
  # value = Rafini.bang!('Ooops! Not perfect?') do
30
30
  # # Perfect code here...
31
31
  # end
32
- def Rafini.bang!(message=nil, bang=Exception, &block)
32
+ def Rafini.bang!(message=nil, bang=::Exception, &block)
33
33
  value = nil
34
34
  begin
35
35
  value = block.call
@@ -52,6 +52,6 @@ end
52
52
  # end
53
53
  # With the following below, I'll be able to say
54
54
  # Rafini.thread_bang!('blah blah...'){ ...stuff... }
55
- def Rafini.thread_bang!(header=nil, bang=Exception, &block)
55
+ def Rafini.thread_bang!(header=nil, bang=::Exception, &block)
56
56
  Thread.new{Rafini.bang!(header, bang, &block)}
57
57
  end
data/lib/rafini/hash.rb CHANGED
@@ -3,30 +3,17 @@ 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
- # {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)
14
+ # {a:'A',b:'B'}.supplement({b:'X',c:'C'},{c:'Y',d:'D'})
15
+ # #=> {a:'A',b:'B',c:'C',d:'D'}
16
+ def supplement!(*hashes)
30
17
  hashes.each do |hash|
31
18
  hash.each do |key, value|
32
19
  self[key] = value unless self.has_key?(key)
@@ -34,30 +21,24 @@ module Rafini
34
21
  end
35
22
  self
36
23
  end
24
+ def supplement(...)
25
+ self.dup.supplement!(...)
26
+ end
37
27
 
38
- # hash0.ammend(hash1,...)
28
+ # hash0.amend(hash1,...)
39
29
  #
40
30
  # 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
31
+ # Overwrites existing keys
32
+ # only with first key value found in amending hashes.
33
+ # {a:'A',b:'B'}.amend({b:'X',c:'C'},{c:'Y',d:'D'}) #=> {a:'A',b:'X'}
34
+ def amend!(*hashes)
35
+ self.each_key do |key|
36
+ value=hashes.find{_1.has_key? key}&.fetch(key) and self[key]=value
51
37
  end
52
38
  self
53
39
  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[_]}
40
+ def amend(...)
41
+ self.dup.amend!(...)
61
42
  end
62
43
  end
63
44
  end
@@ -5,21 +5,25 @@ module Rafini
5
5
  # Kinda hard to explain...
6
6
  # 123.odometer(10,10) #=> [3,2,1]
7
7
  # 30.odometer(2,3,5) #=> [0,0,0,1]
8
- # ((60*60*24)*3 + (60*60)*12 + 60*15 + 30).odometer(60,60,24) #=> [30, 15, 12, 3]
8
+ # ((60*60*24)*3 + (60*60)*12 + 60*15 + 30).odometer(60,60,24)
9
+ # #=> [30, 15, 12, 3]
9
10
  # Useful for making clocks, number scales, mayan long count... etc.
10
- def odometer(*p)
11
- n = self
12
- m = p.inject(1,:*)
13
- r = []
11
+ def odometer(*levels, factors: true)
12
+ raise RangeError, 'negative odometer' if self < 0
13
+ readings, remainder = [], self
14
14
 
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
15
+ levels = levels.inject([1]){|m, f| m.push(m.last*f)} if factors
16
+ levels.shift
17
+
18
+ levels.reverse_each do |level|
19
+ # in case of a float, floor
20
+ reading = (remainder/level).floor
21
+ readings.unshift reading
22
+ remainder = remainder%level
19
23
  end
20
- r.unshift n
21
24
 
22
- return r
25
+ # in case of a float, round
26
+ readings.unshift remainder.round
23
27
  end
24
28
  end
25
29
  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
@@ -0,0 +1,42 @@
1
+ module Rafini
2
+ module Requires
3
+ refine ::String do
4
+ # satisfies?:
5
+ # "1.2.3".satisfies?('~>1.1') #=> true
6
+ # "1.2.3".satisfies?('~>2.3') #=> false
7
+ def satisfies?(*reqs)
8
+ Gem::Requirement.new(*reqs).satisfied_by? Gem::Version.new(self)
9
+ end
10
+ end
11
+
12
+ refine ::Kernel do
13
+ def requires(*list)
14
+ loaded = []
15
+ list.each do |gems|
16
+ gems.lines.each do |gemname_reqs|
17
+ gemname, *reqs = gemname_reqs.split
18
+ next unless gemname
19
+ unless reqs.empty?
20
+ case gemname
21
+ when 'rafini'
22
+ unless VERSION.satisfies?(*reqs)
23
+ raise "helpema #{VERSION} not #{reqs.join(', ')}"
24
+ end
25
+ next
26
+ when 'ruby'
27
+ unless RUBY_VERSION.satisfies?(*reqs)
28
+ raise "ruby #{RUBY_VERSION} not #{reqs.join(', ')}"
29
+ end
30
+ next
31
+ else
32
+ gem gemname, *reqs
33
+ end
34
+ end
35
+ require gemname and loaded.push gemname
36
+ end
37
+ end
38
+ return loaded
39
+ end
40
+ end
41
+ end
42
+ end
data/lib/rafini/string.rb CHANGED
@@ -4,17 +4,24 @@ 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
+ end
19
+
20
+ # shellescape:
21
+ # Same funtionality as Shellword's String#shellescape
22
+ def shellescape
23
+ # This is a contraction of Shellwords.escape function
24
+ self.gsub(/[^\w\-.,:+\/@\n]/,'\\\\\\&').gsub(/\n/,"'\n'")
18
25
  end
19
26
  end
20
27
  end
data/lib/rafini.rb CHANGED
@@ -1,12 +1,17 @@
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.1.221212'
3
+ # Constants
4
+ autoload :Empty, 'rafini/empty'
5
+ # Pure
6
+ autoload :Array, 'rafini/array'
7
+ autoload :Hash, 'rafini/hash'
8
+ autoload :Integer, 'rafini/integer'
9
+ autoload :String, 'rafini/string'
10
+ # Hybrid
11
+ autoload :Exception, 'rafini/exception'
12
+ # Mix
13
+ autoload :Odometers, 'rafini/odometers'
14
+ autoload :Requires, 'rafini/requires'
10
15
  end
11
16
  # Requires:
12
17
  #`ruby`
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.1.221212
5
5
  platform: ruby
6
6
  authors:
7
- - carlosjhr64
7
+ - CarlosJHR64
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-15 00:00:00.000000000 Z
11
+ date: 2022-12-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Just a collection of useful refinements.
14
14
 
@@ -26,6 +26,7 @@ files:
26
26
  - lib/rafini/hash.rb
27
27
  - lib/rafini/integer.rb
28
28
  - lib/rafini/odometers.rb
29
+ - lib/rafini/requires.rb
29
30
  - lib/rafini/string.rb
30
31
  homepage: https://github.com/carlosjhr64/rafini
31
32
  licenses:
@@ -46,8 +47,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
47
  - !ruby/object:Gem::Version
47
48
  version: '0'
48
49
  requirements:
49
- - 'ruby: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]'
50
- rubygems_version: 3.1.2
50
+ - 'ruby: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]'
51
+ rubygems_version: 3.3.7
51
52
  signing_key:
52
53
  specification_version: 4
53
54
  summary: Just a collection of useful refinements.