bblib 0.3.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +11 -10
- data/.rspec +2 -2
- data/.travis.yml +4 -4
- data/CODE_OF_CONDUCT.md +13 -13
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +247 -757
- data/Rakefile +6 -6
- data/bblib.gemspec +34 -34
- data/bin/console +14 -14
- data/bin/setup +7 -7
- data/lib/array/bbarray.rb +71 -29
- data/lib/bblib.rb +12 -12
- data/lib/bblib/version.rb +3 -3
- data/lib/class/effortless.rb +23 -0
- data/lib/error/abstract.rb +3 -0
- data/lib/file/bbfile.rb +93 -52
- data/lib/hash/bbhash.rb +130 -46
- data/lib/hash/hash_struct.rb +24 -0
- data/lib/hash/tree_hash.rb +364 -0
- data/lib/hash_path/hash_path.rb +210 -0
- data/lib/hash_path/part.rb +83 -0
- data/lib/hash_path/path_hash.rb +84 -0
- data/lib/hash_path/proc.rb +93 -0
- data/lib/hash_path/processors.rb +239 -0
- data/lib/html/bbhtml.rb +2 -0
- data/lib/html/builder.rb +34 -0
- data/lib/html/tag.rb +49 -0
- data/lib/logging/bblogging.rb +42 -0
- data/lib/mixins/attrs.rb +422 -0
- data/lib/mixins/bbmixins.rb +7 -0
- data/lib/mixins/bridge.rb +17 -0
- data/lib/mixins/family_tree.rb +41 -0
- data/lib/mixins/hooks.rb +139 -0
- data/lib/mixins/logger.rb +31 -0
- data/lib/mixins/serializer.rb +71 -0
- data/lib/mixins/simple_init.rb +160 -0
- data/lib/number/bbnumber.rb +15 -7
- data/lib/object/bbobject.rb +46 -19
- data/lib/opal/bbopal.rb +0 -4
- data/lib/os/bbos.rb +24 -16
- data/lib/os/bbsys.rb +60 -43
- data/lib/string/bbstring.rb +165 -66
- data/lib/string/cases.rb +37 -29
- data/lib/string/fuzzy_matcher.rb +48 -50
- data/lib/string/matching.rb +43 -30
- data/lib/string/pluralization.rb +156 -0
- data/lib/string/regexp.rb +45 -0
- data/lib/string/roman.rb +17 -30
- data/lib/system/bbsystem.rb +42 -0
- data/lib/time/bbtime.rb +79 -58
- data/lib/time/cron.rb +174 -132
- data/lib/time/task_timer.rb +86 -70
- metadata +27 -10
- data/lib/gem/bbgem.rb +0 -28
- data/lib/hash/hash_path.rb +0 -344
- data/lib/hash/hash_path_proc.rb +0 -256
- data/lib/hash/path_hash.rb +0 -81
- data/lib/object/attr.rb +0 -182
- data/lib/object/hooks.rb +0 -69
- data/lib/object/lazy_class.rb +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 33086855ce2bd5a595df8e5f0ab6a5f7260c201077bb2546e5d2650a94912610
|
4
|
+
data.tar.gz: 8ac3e610c21f45e78fe52db56d22c411b281fd7c09d50e835426e62a24310f42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 235ff9ade8bee91f013d4a6a688bb859f5aaf73421b280cd594323677c7107539ac381481632b996d3aebd809492a5784d6065deb3d18ed4aea9210c56de2b1a
|
7
|
+
data.tar.gz: 12aa12de2bc99b083b58727084f3b753eae6f892dd963163611fc3423bb3b1ec981ac509c1867b119da078c9d851d3610d9ac464df99e729728fa856f9d5a353
|
data/.gitignore
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
/.bundle/
|
2
|
-
/.yardoc
|
3
|
-
/Gemfile.lock
|
4
|
-
/_yardoc/
|
5
|
-
/coverage/
|
6
|
-
/doc/
|
7
|
-
/pkg/
|
8
|
-
/spec/reports/
|
9
|
-
/tmp/
|
10
|
-
*.gem
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/Gemfile.lock
|
4
|
+
/_yardoc/
|
5
|
+
/coverage/
|
6
|
+
/doc/
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/tmp/
|
10
|
+
*.gem
|
11
|
+
smells.html
|
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
--format documentation
|
2
|
-
--color
|
1
|
+
--format documentation
|
2
|
+
--color
|
data/.travis.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 2.1.6
|
4
|
-
before_install: gem install bundler -v 1.10.6
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.1.6
|
4
|
+
before_install: gem install bundler -v 1.10.6
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
# Contributor Code of Conduct
|
2
|
-
|
3
|
-
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
-
|
5
|
-
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
-
|
7
|
-
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
-
|
9
|
-
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
-
|
11
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
-
|
13
|
-
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in bblib.gemspec
|
4
|
-
gemspec
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in bblib.gemspec
|
4
|
+
gemspec
|
data/LICENSE.txt
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2015 Brandon
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
13
|
-
all copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
THE SOFTWARE.
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Brandon
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,757 +1,247 @@
|
|
1
|
-
# BBLib
|
2
|
-
|
3
|
-
BBLib
|
4
|
-
|
5
|
-
Good news! BBLib is now compatible with Opal! Well, like 90% compatible, but it can be 100% compiled into Javascript. Only very small tweaks were made to support this, so base functionality for the BBLib outside of Opal remains the same. But now it can coexist as both a Ruby gem, and an Opal library.
|
6
|
-
|
7
|
-
BBLib contains A LOT of functionality, but is a very small, lightweight library. As such, it can be hard to document everything that is included (and even harder to make a TL:DR version).
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
# =>
|
38
|
-
|
39
|
-
#
|
40
|
-
|
41
|
-
# =>
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
#
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
```ruby
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
#
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
"
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
#
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
#
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
```ruby
|
249
|
-
number = 17
|
250
|
-
BBLib.keep_between number, 0, 10
|
251
|
-
#=> 10
|
252
|
-
|
253
|
-
number = 0.145
|
254
|
-
BBLib.keep_between number, 0.5, 1
|
255
|
-
#=> 0.5
|
256
|
-
|
257
|
-
number = -250
|
258
|
-
BBLib.keep_betwee number, nil, 100
|
259
|
-
#=> -250
|
260
|
-
```
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
### String
|
265
|
-
|
266
|
-
#### FuzzyMatcher
|
267
|
-
|
268
|
-
FuzzyMatcher (BBLib::FuzzyMatcher) is a class for making fuzzy comparisons with strings. It implements a weighted algorithm system which uses the algorithms listed below to generate a percentage based match between two strings. There are various settings that can be toggled in addition. These settings are:
|
269
|
-
|
270
|
-
* **Case Sensitive**: Toggles whether or not strings should be compared in a case sensitive manor.
|
271
|
-
* **Remove Symbols**: Toggle to remove all symbols from the strings before comparing them.
|
272
|
-
* **Move Articles**: Toggling this normalizes the position on preceding or trailing articles (the, an, a).
|
273
|
-
* **Convert Roman**: When toggled to true, all roman numerals found in the strings are converted to integers.
|
274
|
-
|
275
|
-
Current algorithms are:
|
276
|
-
* Levenshtein
|
277
|
-
* Composition
|
278
|
-
* Phrase
|
279
|
-
* Numeric
|
280
|
-
|
281
|
-
```ruby
|
282
|
-
# Create a FuzzyMatcher and set it to be case insensitive
|
283
|
-
fm = BBLib::FuzzyMatcher.new case_sensitive: false
|
284
|
-
|
285
|
-
# Set the weight of two of the algorithms. A weight of zero effectively turns off that algorithm.
|
286
|
-
fm.set_weight :levenshtein, 10
|
287
|
-
fm.set_weight :composition, 5
|
288
|
-
|
289
|
-
# Get similarity as a %
|
290
|
-
fm.similarity 'Ruby', 'Rails'
|
291
|
-
#=> 20.0
|
292
|
-
|
293
|
-
# Set the threshold match percent
|
294
|
-
fm.threshold = 50
|
295
|
-
# Returns true if the match percent is greater than or equal to the threshold
|
296
|
-
fm.match? 'Ruby', 'Rails'
|
297
|
-
#=> false
|
298
|
-
|
299
|
-
# Get the similarity of a string with an Array of strings. A hash is returned
|
300
|
-
# with the key being the string compared and the value being its match %
|
301
|
-
fm.similarities 'Ruby', ['Ruby', 'Rails', 'Java', 'C++']
|
302
|
-
#=> {"Ruby"=>100.0, "Rails"=>20.0, "Java"=>0.0, "C++"=>0.0}
|
303
|
-
|
304
|
-
# Compare a string to an Array of strings but return only the match with the highest comparison result
|
305
|
-
fm.best_match 'Ruby', ['Ruby', 'Rails', 'Java', 'C++']
|
306
|
-
#=> 'Ruby'
|
307
|
-
```
|
308
|
-
|
309
|
-
|
310
|
-
#### String Comparisons
|
311
|
-
|
312
|
-
**ALGORITHIMS**
|
313
|
-
|
314
|
-
Implementations of the following algorithms are currently available. All algorithms are for calculating similarity between strings. Most are useful for fuzzy matching. All algorithms are available statically in the BBLib module but are also available as extensions to the String class. Most of these algorithms are case sensitive by default.
|
315
|
-
|
316
|
-
__1 - Levenshtein Distance__
|
317
|
-
|
318
|
-
A fairly simple rendition of the Levenshtein distance algorithm in Ruby. There are two functions available: **levenshtein_distance** and **levenshtein_similarity**. The former, calculates the number of additions, removals or substitutions needed to turn one string into another. The latter, uses the distance to calculate a percentage based match of two strings.
|
319
|
-
|
320
|
-
```ruby
|
321
|
-
# Get the Levenshtein distance of two strings
|
322
|
-
'Ruby is great'.levenshtein_distance 'Rails is great'
|
323
|
-
# OR
|
324
|
-
BBLib.levenshtein_distance 'Ruby is great', 'Rails is great'
|
325
|
-
#=> 4
|
326
|
-
|
327
|
-
# Or calculate the similarity as a percent
|
328
|
-
'Ruby is great'.levenshtein_similarity 'Rails is great'
|
329
|
-
#=> 71.42857142857143
|
330
|
-
```
|
331
|
-
|
332
|
-
__2 - String Composition__
|
333
|
-
|
334
|
-
Compares the character composition of two strings. The order of characters is not relevant, however, the number of occurrences is factored in.
|
335
|
-
|
336
|
-
```ruby
|
337
|
-
'Ruby is great'.composition_similarity 'Rails is great'
|
338
|
-
#=> 71.42857142857143
|
339
|
-
```
|
340
|
-
|
341
|
-
__3 - Phrase Similarity__
|
342
|
-
|
343
|
-
Checks to see how many words in a string match another. Words must match exactly, including case. The results is the percentage of words that have an exact pair. The number of occurrences is also a factor.
|
344
|
-
|
345
|
-
```ruby
|
346
|
-
'Learn Ruby, it is great'.phrase_similarity 'Learn Rails; it is awesome'
|
347
|
-
#=> 60.0
|
348
|
-
|
349
|
-
'ruby, ruby, ruby'.phrase_similarity 'ruby ruby'
|
350
|
-
#=> 66.66666666666666
|
351
|
-
```
|
352
|
-
|
353
|
-
__4 - Numeric Similarity _(In Progress)_ __
|
354
|
-
|
355
|
-
This algorithm is currently undergoing refactoring...
|
356
|
-
|
357
|
-
This is primarily for comparing titles (such as movie or game titles). As an example, other algorithms would conclude that _'Terminator 2'_ is more similar to _'Terminator'_ than _'Terminator 2: Judgement Day'_, but the best match may really be _'Terminator 2: Judgement Day'_. To fix this, the numeric similarity would weight more towards the more appropriate title that contains the same number or numbers as itself. A string with no numbers is effectively considered to include a 1 for comparison's sake.
|
358
|
-
|
359
|
-
```ruby
|
360
|
-
a = 'Terminator 2'
|
361
|
-
b = 'Terminator 2: Judgement Day'
|
362
|
-
c = 'Terminator'
|
363
|
-
|
364
|
-
puts a.levenshtein_similarity c
|
365
|
-
#=> 83.33333333333334
|
366
|
-
puts a.numeric_similarity c
|
367
|
-
#=> 33.33333333333333
|
368
|
-
|
369
|
-
puts a.levenshtein_similarity b
|
370
|
-
#=> 44.44444444444444
|
371
|
-
puts a.numeric_similarity b
|
372
|
-
#=> 100.0
|
373
|
-
```
|
374
|
-
This algorithm is generally only useful when combined with another algorithm, which is exactly what the FuzzyMatcher class does.
|
375
|
-
|
376
|
-
__5 - QWERTY Similarity__
|
377
|
-
|
378
|
-
A basic method that compares two strings by measuring the physical difference from one char to another on a QWERTY keyboard (alpha-numeric only). May be useful for detecting typos in words, but becomes less useful depending on the length of the string. This method is still in development and not yet in a final state. Currently a total distance is returned. Eventually, a percentage based match will replace this.
|
379
|
-
|
380
|
-
```ruby
|
381
|
-
'q'.qwerty_distance 's'
|
382
|
-
#=> 2
|
383
|
-
|
384
|
-
'qwerty'.qwerty_distance 'qsertp'
|
385
|
-
#=> 5
|
386
|
-
```
|
387
|
-
|
388
|
-
#### Roman Numeral
|
389
|
-
|
390
|
-
**to_roman**
|
391
|
-
|
392
|
-
Converts an integer into a roman numeral. Supports numbers up to 1000 ('M'). Anything greater will simply return a string version of the integer. Can be called directly on any Fixnum object as well as from the BBLib module.
|
393
|
-
|
394
|
-
```ruby
|
395
|
-
BBLib.to_roman 20
|
396
|
-
#=> 'XX'
|
397
|
-
|
398
|
-
15.to_roman
|
399
|
-
#=> 'XV'
|
400
|
-
```
|
401
|
-
|
402
|
-
**string_to_roman**
|
403
|
-
|
404
|
-
Converts any integers found in a string into their roman numeral equivalent. Numbers will only be converted if they are surrounded by white space or by symbols. If the integer is embedded within alpha characters or contains a decimal, it is left untouched.
|
405
|
-
|
406
|
-
The method is also extended to the String class to be called directly.
|
407
|
-
|
408
|
-
```ruby
|
409
|
-
BBLib.string_to_roman "Toy Story 3"
|
410
|
-
#= "Toy Story III"
|
411
|
-
|
412
|
-
"Die Hard 2: Die Harder".to_roman
|
413
|
-
#=> "Die Hard II: Die Harder"
|
414
|
-
|
415
|
-
"Left4Dead".to_roman
|
416
|
-
#=> "Left4Dead"
|
417
|
-
|
418
|
-
"Ruby 2.2".to_roman
|
419
|
-
#=> "Ruby 2.2"
|
420
|
-
```
|
421
|
-
|
422
|
-
**from_roman**
|
423
|
-
|
424
|
-
The opposite of _string_to_roman_. Parses a string for roman numerals and converts them into integers. Also extended to the String class to call directly. Works similarly to _to_roman_ in that numerals are converted only if surrounded by white space or symbols.
|
425
|
-
|
426
|
-
```ruby
|
427
|
-
BBLib.from_roman "Toy Story III"
|
428
|
-
#=> 'Toy Story 3'
|
429
|
-
|
430
|
-
"Super Mario Land II: Six Golden Coins".from_roman
|
431
|
-
#=> 'Super Mario Land 2: Six Golden Coins'
|
432
|
-
|
433
|
-
"Donkey Kong CountryIII".from_roman
|
434
|
-
#=> 'Donkey Kong CountryIII'
|
435
|
-
```
|
436
|
-
|
437
|
-
#### Case Converters
|
438
|
-
|
439
|
-
Some basic case converters are now available. The majority of these are complete but not heavily tested, so some bugs or edge cases may exist.
|
440
|
-
|
441
|
-
Case supported:
|
442
|
-
* Title Case
|
443
|
-
* Start Case
|
444
|
-
* Camel Case
|
445
|
-
* Snake Case
|
446
|
-
* Spinal Case
|
447
|
-
* Train Case
|
448
|
-
* Delimited Case
|
449
|
-
|
450
|
-
Each case may be called directly on a string or using class methods in the BBLib module.
|
451
|
-
|
452
|
-
```ruby
|
453
|
-
sent = 'This is a casing-test. OK?'
|
454
|
-
|
455
|
-
puts sent.title_case
|
456
|
-
#=> This Is a Casing-Test. Ok?
|
457
|
-
|
458
|
-
puts sent.start_case
|
459
|
-
#=> This Is A Casing-Test. Ok?
|
460
|
-
|
461
|
-
puts sent.snake_case
|
462
|
-
#=> This_is_a_casing_test_OK
|
463
|
-
|
464
|
-
puts sent.spinal_case
|
465
|
-
#=> This-is-a-casing-test-OK
|
466
|
-
|
467
|
-
puts sent.train_case
|
468
|
-
#=> This-Is-A-Casing-Test-Ok
|
469
|
-
|
470
|
-
puts sent.delimited_case '+'
|
471
|
-
#=> This+is+a+casing+test+OK
|
472
|
-
|
473
|
-
# By default when title casing or start casing, the capitalize method is used on each word.
|
474
|
-
# This results in characters following the first to be downcased. To avoid this, the first_only param can be used.
|
475
|
-
# This param prevents all other chars in a word from being processed.
|
476
|
-
puts 'i like SQL'.title_case
|
477
|
-
#=> 'I Like Sql'
|
478
|
-
|
479
|
-
puts 'i like SQL'.title_case first_only: true
|
480
|
-
#=> I Like SQL
|
481
|
-
```
|
482
|
-
|
483
|
-
#### Other
|
484
|
-
|
485
|
-
**msplit** _aka multi split_
|
486
|
-
|
487
|
-
_msplit_ is similar to the String method split, except it can take an array of string delimiters rather than a single delimiter. The string is split be each delimiter in order and an Array is returned. msplit may also be called on an array to split elements within it.
|
488
|
-
|
489
|
-
```ruby
|
490
|
-
"This_is.a&&&&test".msplit '_', '.', '&'
|
491
|
-
|
492
|
-
#=> ['This', 'is', 'a', 'test']
|
493
|
-
```
|
494
|
-
|
495
|
-
By default any empty items from the returned Array are removed. This behavior can be changed using the _:keep_empty_ named param.
|
496
|
-
|
497
|
-
```ruby
|
498
|
-
"This_is.a&&&&test".msplit ['_', '.', '&'], keep_empty: true
|
499
|
-
|
500
|
-
#=> ['This', 'is', 'a', '', '', '', 'test']
|
501
|
-
```
|
502
|
-
|
503
|
-
**move_articles**
|
504
|
-
|
505
|
-
This method is used to normalize strings that contain titles. It parses a string and checks to see if _the_, _an_ or _a_ are in the title, either preceding or trailing. If they are found they are moved to the front, back or removed depending on the argument passed to _position_.
|
506
|
-
|
507
|
-
The method is available via the BBLib module or any instance of String.
|
508
|
-
|
509
|
-
```ruby
|
510
|
-
title = "The Simpsons"
|
511
|
-
title.move_articles :back
|
512
|
-
#=> "Simpons, The"
|
513
|
-
|
514
|
-
title.move_articles :none
|
515
|
-
#=> "Simpsons"
|
516
|
-
|
517
|
-
title = "Day to Remember, A"
|
518
|
-
title.move_articles :front
|
519
|
-
#=> "A Day to Remember"
|
520
|
-
```
|
521
|
-
|
522
|
-
**extract_integers**/**extract_floats**/**extract_numbers**
|
523
|
-
|
524
|
-
Three methods to grab numbers from within strings. Integers only nabs numbers with no decimal places, floats gets only numbers with a decimal and numbers gets both integers and floats. The numbers must also be properly formatted, so something like the version number '2.1.1' below will not be extracted.
|
525
|
-
|
526
|
-
```ruby
|
527
|
-
s = 'Test 10 2.5 Number 100 aaaa 10.113 Version 2.1.1'
|
528
|
-
|
529
|
-
p s.extract_integers
|
530
|
-
#=> [10, 100]
|
531
|
-
p s.extract_floats
|
532
|
-
#=> [2.5, 10.113]
|
533
|
-
p s.extract_numbers
|
534
|
-
#=> [10, 2.5, 100, 10.113]
|
535
|
-
```
|
536
|
-
|
537
|
-
### Time
|
538
|
-
|
539
|
-
#### Cron
|
540
|
-
|
541
|
-
BBLib includes a lightweight cron syntax parser. It can be used to display the runtimes of a cron based on a cron string. Nearly every variant of cron syntax is supported with the ability to intermix ranges, divisors and explicit numbers in the same interval placing.
|
542
|
-
|
543
|
-
```ruby
|
544
|
-
|
545
|
-
cron = BBLib::Cron.new('* * * * * *')
|
546
|
-
puts cron.next
|
547
|
-
#=> 2016-04-03 22:01:00 -0600
|
548
|
-
|
549
|
-
puts cron.previous
|
550
|
-
#=> 2016-04-03 21:59:00 -0600
|
551
|
-
|
552
|
-
p cron.next(5)
|
553
|
-
#=> [2016-04-03 22:01:00 -0600, 2016-04-03 22:02:00 -0600, 2016-04-03 22:03:00 -0600, 2016-04-03 22:04:00 -0600, 2016-04-03 22:05:00 -0600]
|
554
|
-
|
555
|
-
# Set the time explicitly. The default is the current system time.
|
556
|
-
puts cron.next(time: Time.now+30)
|
557
|
-
#=> 2016-04-03 22:31:00 -0600
|
558
|
-
```
|
559
|
-
|
560
|
-
An instantiated Cron object is not necessary to get the next and previous times.
|
561
|
-
|
562
|
-
```ruby
|
563
|
-
puts BBLib::Cron.next('* * * * * *')
|
564
|
-
#=> 2016-04-03 22:04:00 -0600
|
565
|
-
|
566
|
-
puts BBLib::Cron.next('0-5 * * * * *')
|
567
|
-
#=> 2016-04-03 22:04:00 -0600
|
568
|
-
|
569
|
-
puts BBLib::Cron.next('0 1 1 1 1 *')
|
570
|
-
#=> 2018-01-01 01:00:00 -0700
|
571
|
-
|
572
|
-
puts BBLib::Cron.next('1 1 1-5 * * 2020')
|
573
|
-
#=> 2020-01-01 01:01:00 -0700
|
574
|
-
|
575
|
-
puts BBLib::Cron.next('*/5 * * * * *')
|
576
|
-
#=> 2016-04-03 22:05:00 -0600
|
577
|
-
|
578
|
-
puts BBLib::Cron.next('1-3,4,5,10-11 1-10 */5 * * *')
|
579
|
-
#=> 2016-04-06 01:01:00 -0600
|
580
|
-
```
|
581
|
-
|
582
|
-
Named days of the week and month are also supported in various formats and can be used in ranges or comma separated lists. They can even the intermingled with numbers such as 'Jun-9'.
|
583
|
-
|
584
|
-
```ruby
|
585
|
-
puts BBLib::Cron.next('* * * * sun *')
|
586
|
-
#=> 2016-04-10 00:00:00 -0600
|
587
|
-
|
588
|
-
puts BBLib::Cron.next('* * * * sunday *')
|
589
|
-
#=> 2016-04-10 00:00:00 -0600
|
590
|
-
|
591
|
-
puts BBLib::Cron.next('* * * * sun,sat *')
|
592
|
-
#=> 2016-04-09 00:00:00 -0600
|
593
|
-
|
594
|
-
puts BBLib::Cron.next('* * * Jun-Dec * *')
|
595
|
-
#=> 2016-06-01 00:00:00 -0600
|
596
|
-
|
597
|
-
# The next Friday the 13th in December
|
598
|
-
puts BBLib::Cron.next('* * 13 Dec Fri *')
|
599
|
-
#=> 2019-12-13 00:00:00 -0700
|
600
|
-
|
601
|
-
# The next leap year
|
602
|
-
puts BBLib::Cron.next('* * 29 February * *')
|
603
|
-
#=> 2020-02-29 00:00:00 -0700
|
604
|
-
|
605
|
-
# The next Feb 29th that also happens to be a Monday
|
606
|
-
puts BBLib::Cron.next('* * 29 February Monday *')
|
607
|
-
#=> 2044-02-29 00:00:00 -0700
|
608
|
-
```
|
609
|
-
|
610
|
-
Common Vixie-isms are also supported:
|
611
|
-
|
612
|
-
```ruby
|
613
|
-
puts BBLib::Cron.next('@daily')
|
614
|
-
#=> 2016-04-04 00:00:00 -0600
|
615
|
-
|
616
|
-
puts BBLib::Cron.next('@weekly')
|
617
|
-
#=> 2016-04-10 00:00:00 -0600
|
618
|
-
```
|
619
|
-
|
620
|
-
_Supported list of Vixie-isms: @daily, @midnight, @noon, @weekly, @monthly, @yearly, @annually_
|
621
|
-
_Note: @reboot and @restart can be parsed but are inaccurate due to the fact that they have no way of knowing the next reboot._
|
622
|
-
|
623
|
-
#### Duration parser
|
624
|
-
|
625
|
-
**Parsing a duration from String**
|
626
|
-
|
627
|
-
Similar to the file size parser under the files section, but instead can parse duration from know time patterns in a string. By default the result is returned in seconds, but this can be changed using the named param _:output_. The method is also extended to the String class directly.
|
628
|
-
|
629
|
-
```ruby
|
630
|
-
"1hr 10 minutes 11s".parse_duration
|
631
|
-
|
632
|
-
#=> 4211.0
|
633
|
-
|
634
|
-
"1hr 10 minutes 11s".parse_duration output: :hour
|
635
|
-
|
636
|
-
#=> 1.1697222222222223
|
637
|
-
```
|
638
|
-
Output options are:
|
639
|
-
* :yocto
|
640
|
-
* :zepto
|
641
|
-
* :atto
|
642
|
-
* :femto
|
643
|
-
* :pico
|
644
|
-
* :nano
|
645
|
-
* :micro
|
646
|
-
* :milli
|
647
|
-
* :sec
|
648
|
-
* :min
|
649
|
-
* :hour
|
650
|
-
* :day
|
651
|
-
* :week
|
652
|
-
* :month
|
653
|
-
* :year
|
654
|
-
|
655
|
-
__WARNING:__ _time intervals below microseconds are prone to heavy rounding errors in the current implementation. They are NOT EXACT._
|
656
|
-
|
657
|
-
The colon separated duration pattern (eg. '02:30') can also be matched. The last set of digits is treated as seconds with each prior number being one interval greater. The default starting interval can be changed using the __min_interval__ named param. The available options are the same as the output options. This pattern type can even be intermixed with the types shown above and will be added to the total duration.
|
658
|
-
|
659
|
-
```ruby
|
660
|
-
duration = '04:35'
|
661
|
-
|
662
|
-
puts duration.parse_duration
|
663
|
-
#=> 275.0
|
664
|
-
|
665
|
-
puts duration.parse_duration min_interval: :min
|
666
|
-
#=> 16500.0
|
667
|
-
```
|
668
|
-
|
669
|
-
**Create a duration String from Numeric**
|
670
|
-
|
671
|
-
There is also a method to turn a Numeric object into a string representation of a duration. This method is extended to the Numeric class. An input may be specified to tell the method what the input number represents. The options for this are the same as the output options listed above. A stop can be added using any of those same options. This will prevent the string from containing anything below the specified time type. For instance, specifying _stop: :sec_ will prevent milliseconds from being included if there are any. There are also three options that can be passed to the _:style_ argument to change the output (options are _:full_, _:medium_ and _:short:).
|
672
|
-
|
673
|
-
```ruby
|
674
|
-
9645.to_duration
|
675
|
-
#=> '2 hrs 40 mins 45 secs'
|
676
|
-
|
677
|
-
101.to_duration input: :hour
|
678
|
-
#=> '4 days 5 hrs'
|
679
|
-
|
680
|
-
20.56.to_duration input: :hour, style: :full
|
681
|
-
#=> '20 hours 33 minutes 36 seconds'
|
682
|
-
|
683
|
-
20.56123.to_duration input: :hour, style: :medium, stop: :min
|
684
|
-
#=> '20 hrs 33 mins'
|
685
|
-
|
686
|
-
123124.to_duration( style: :short)
|
687
|
-
#=> '34h 12m 4s'
|
688
|
-
```
|
689
|
-
|
690
|
-
#### Task Timer
|
691
|
-
|
692
|
-
A very simple task timer is also included. It is not intended to replace benchmarking classes but rather to augment or be used for simplistic timing. You simply need to instantiate a timer and then call start with the name of the task. To stop the timer, call stop and pass in the same task name. Once a single time has been completed for any given task a few different metrics can be pulled on that task. These metrics may also be printed in bulk using the _stats_ method.
|
693
|
-
|
694
|
-
```ruby
|
695
|
-
# Generate a new timer object
|
696
|
-
t = BBLib::TaskTimer.new
|
697
|
-
|
698
|
-
# Call start right before initiating a task and stop immediately after.
|
699
|
-
5.times do
|
700
|
-
t.start :random_sleep
|
701
|
-
# Perform task...
|
702
|
-
sleep(rand())
|
703
|
-
t.stop :random_sleep
|
704
|
-
end
|
705
|
-
|
706
|
-
# Print out the stats from the task
|
707
|
-
puts t.stats :random_sleep
|
708
|
-
#=> random_sleep
|
709
|
-
#=> ------------------------------
|
710
|
-
#=> Count 5
|
711
|
-
#=> First 0.3134028911590576
|
712
|
-
#=> Last 0.5248761177062988
|
713
|
-
#=> Min 0.20781898498535156
|
714
|
-
#=> Max 0.9016561508178711
|
715
|
-
#=> Avg 0.4677897930145264
|
716
|
-
#=> Sum 2.338948965072632
|
717
|
-
|
718
|
-
# Same as above but cnverts seconds into human readable time durations.
|
719
|
-
# The pretty argument may also be applied to individual stat calls such as avg, sum, min, max, etc...
|
720
|
-
puts t.stats :random_sleep, pretty: true
|
721
|
-
#=> random_sleep
|
722
|
-
#=> ------------------------------
|
723
|
-
#=> Count 5
|
724
|
-
#=> First 313 mils
|
725
|
-
#=> Last 525 mils
|
726
|
-
#=> Min 208 mils
|
727
|
-
#=> Max 902 mils
|
728
|
-
#=> Avg 468 mils
|
729
|
-
#=> Sum 2 secs 339 mils
|
730
|
-
|
731
|
-
# Similar to the above task, this version uses a restart which stops the first start call and initiates a new timer
|
732
|
-
t.start :another_task
|
733
|
-
5.times do
|
734
|
-
sleep(rand())
|
735
|
-
t.restart :another_task
|
736
|
-
end
|
737
|
-
|
738
|
-
# Get the individual average stat for another task. Method calls are aliases so you could also use .average or .av to get the average.
|
739
|
-
puts t.avg :another_task
|
740
|
-
#=> 0.5790667057037353
|
741
|
-
```
|
742
|
-
|
743
|
-
By default the task timer will only keep the stats from 100 runs of each task it tracks. The retention can be increased or decreased using the _retention_ method. Also, call stop will return the total time the stopped task ran.
|
744
|
-
|
745
|
-
## Development
|
746
|
-
|
747
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
748
|
-
|
749
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
750
|
-
|
751
|
-
## Contributing
|
752
|
-
|
753
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/bblack16/bblib. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
754
|
-
|
755
|
-
## License
|
756
|
-
|
757
|
-
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
1
|
+
# BBLib
|
2
|
+
|
3
|
+
BBLib is a collection of various methods and classes that aim to extend the Ruby language. One of the primary goals with the BBLib is to keep it as lightweight as possible. This means you will not find dependencies outside of the Ruby core libraries.
|
4
|
+
|
5
|
+
Good news! BBLib is now compatible with Opal! Well, like 90% compatible (some portions are excluded when running in Opal), but it can be 100% compiled into Javascript. Only very small tweaks were made to support this, so base functionality for the BBLib outside of Opal remains the same. But now it can coexist as both a Ruby gem, and an Opal library.
|
6
|
+
|
7
|
+
BBLib contains A LOT of functionality, but is a very small, lightweight library. As such, it can be hard to document everything that is included (and even harder to make a TL:DR version). The usage section below contains most of the highlights and important features. The source code contains the rest.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'bblib'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install bblib
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Hash Path
|
28
|
+
|
29
|
+
HashPath is a set of functions, classes and extensions to the native ruby hash and array classes. It allows to items to be retrieved from a hash using a dot delimited syntax, similar to XPath for XML. It also provides methods for moving, copying and deleting paths within hashes as well as modifying the contents of nested paths with hashes.
|
30
|
+
|
31
|
+
Below are several examples.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
hash = { a: 1, b: 2, c: [3, 4, { d: 5 }, 6], e: { f: { g: 'test', a: 99 } } }
|
35
|
+
|
36
|
+
hash.hpath('a') # Normal hash like navigation
|
37
|
+
# => [1] <- Always returns an array
|
38
|
+
hash.hpath('..a') # Recursive navigation
|
39
|
+
# => [1, 99]
|
40
|
+
hash.hpath('/[abc]/')
|
41
|
+
# => [1, 2, [3, 4, {:d=>5}, 6]]
|
42
|
+
|
43
|
+
hash.hpaths # => View the absolute paths of a hash or array
|
44
|
+
# => ["a", "b", "c.[0]", "c.[1]", "c.[2].d", "c.[3]", "e.f.g", "e.f.a"]
|
45
|
+
|
46
|
+
hash.hpath_move('c.[0]' => 'z') # Array access and moving
|
47
|
+
# => {:a=>1, :b=>2, :c=>[4, {:d=>5}, 6], :e=>{:f=>{:g=>"name", :a=>99}}, :z=>3}
|
48
|
+
hash.hpath_copy('e..g' => 'z', 'a' => 'ary') # Array access and moving
|
49
|
+
# => {:a=>1, :b=>2, :c=>[3, 4, {:d=>5}, 6], :e=>{:f=>{:g=>"name", :a=>99}}, :z=>"name", :ary=>1}
|
50
|
+
hash.hpath_delete('e.f.g') # Delete elements using path notation
|
51
|
+
# => {:a=>1, :b=>2, :c=>[3, 4, {:d=>5}, 6], :e=>{:f=>{:a=>99}}}
|
52
|
+
hash.hpath_set('e.f.g' => 'name') # Set nested value
|
53
|
+
# => {:a=>1, :b=>2, :c=>[3, 4, {:d=>5}, 6], :e=>{:f=>{:g=>"name", :a=>99}}}
|
54
|
+
```
|
55
|
+
|
56
|
+
#### Path options
|
57
|
+
|
58
|
+
- __Standard__ (e.g. 'a') - Matches any key that is either :a or 'a'
|
59
|
+
- __Recursive__ (e.g. '..a') - Matches any key :a or'a' any where in the nested hashes/arrays.
|
60
|
+
- __Regexp__ (e.g. '/example/') - Finds all keys that match the regular expression /example/
|
61
|
+
- __Array Element__ (e.g. '[0]') - Finds the element at index 0.
|
62
|
+
- __Range__ (e.g. '[0..2]') - Returns the first 3 elements of any matching array.
|
63
|
+
- __Parent__ (e.g. '{parent}') - Returns the parent of the current position.
|
64
|
+
- __Root__ (e.g. '{root}') - Navigates to the root of the current Hash/Array.
|
65
|
+
- __Siblings__ (e.g. '{siblings}') - Returns the siblings of the current Hash/Array.
|
66
|
+
- __Expression__ (e.g. 'a(value > 10)') - Returns elements if the expression in the parenthesis evaluates to true. _value_ holds a reference to the current position of navigation. The example would return any items under the key 'a' that have a value greater than 10.
|
67
|
+
|
68
|
+
### TreeHash
|
69
|
+
|
70
|
+
TreeHash is a container that wraps a Hash or Array. It provides all of the navigation and functionality used in HashPath. It provides the ability to navigate hashes both forwards and backwards, similar to the DOM of XML or a webpage.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
hash = { a: 1, b: 2, c: [3, 4, { d: 5 }, 6], e: { f: { g: 'test', a: 99 } } }
|
74
|
+
tree = hash.to_tree_hash
|
75
|
+
|
76
|
+
tree[:e][:f][:g].parent # Standard hash navigation and usage of parent to backtrack
|
77
|
+
# => {:g=>"test", :a=>99}
|
78
|
+
tree.find('e..a') # HashPath uses this method for navigatio. Here it returns an Array of TreeHash objects.
|
79
|
+
# => [99]
|
80
|
+
tree.find('e..a').first.siblings # Get siblings. next_sibling and previous_sibling are also available
|
81
|
+
# => [test]
|
82
|
+
```
|
83
|
+
|
84
|
+
### String
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
str = 'this is an example'
|
88
|
+
|
89
|
+
# Cases
|
90
|
+
str.snake_case
|
91
|
+
# => 'this_is_an_example'
|
92
|
+
str.title_case
|
93
|
+
# => 'This Is an Example'
|
94
|
+
# Also available: start_case, camel_case, train_case, spinal_case, delimited_case(custom)
|
95
|
+
|
96
|
+
# General
|
97
|
+
'12.9 MB version 1.1.9 20 total'.extract_numbers
|
98
|
+
# => [12.9, 20]
|
99
|
+
'12.9 MB version 1.1.9 20 total'.extract_integers
|
100
|
+
# => [20]
|
101
|
+
'12.9 MB version 1.1.9 20 total'.extract_floats
|
102
|
+
# => [12.9]
|
103
|
+
|
104
|
+
'Simpsons, The'.move_articles(:front) # or :back or :none
|
105
|
+
# => 'The Simpsons'
|
106
|
+
|
107
|
+
# Simple shortening with various truncation options
|
108
|
+
str = 'This string is longer than I want it to be for display purposes'
|
109
|
+
BBLib.chars_up_to(str, 10)
|
110
|
+
# => 'This strin...'
|
111
|
+
BBLib.chars_up_to(str, 10, style: :back)
|
112
|
+
# => '...y purposes'
|
113
|
+
BBLib.chars_up_to(str, 10, style: :outter)
|
114
|
+
# => "This ...poses"
|
115
|
+
BBLib.chars_up_to(str, 10, style: :middle)
|
116
|
+
# => "... I want it..."
|
117
|
+
|
118
|
+
# Basic pluralization without the need for large models
|
119
|
+
BBLib.pluralize(1, 'Test')
|
120
|
+
# => 'Test'
|
121
|
+
BBLib.pluralize(2, 'Test')
|
122
|
+
# => 'Tests'
|
123
|
+
BBLib.pluralize(99, 'Quer', 'ies', 'y')
|
124
|
+
# => 'Queries'
|
125
|
+
|
126
|
+
# Multi Split
|
127
|
+
'this is-a+test'.msplit(' ', '-', /\+/)
|
128
|
+
# => ['this', 'is', 'a', 'test']
|
129
|
+
|
130
|
+
# Split unless not in quotes
|
131
|
+
'an,"example,of,some",kind'.quote_split(',')
|
132
|
+
# => ["an", "\"example,of,some\"", "kind"]
|
133
|
+
|
134
|
+
# Regular Expressions
|
135
|
+
'/test/i'.to_regex # Convert the /.../ version of a regex string to a Regex.
|
136
|
+
# => /test/i
|
137
|
+
|
138
|
+
# String encapsulation methods
|
139
|
+
str = 'test'
|
140
|
+
str.encapsulate('[') # Encapsulate a string. Recognizes (, [, { and < as (), [], {} and <>.
|
141
|
+
# => '[test]'
|
142
|
+
str.encapsulate('S')
|
143
|
+
# => 'StestS'
|
144
|
+
str.encap_by?('t') # Check if a string begins and ends with a char or string. Recognizes (, [, { and < as (), [], {} and <>.
|
145
|
+
# => true
|
146
|
+
'(example)'.uncapsulate('(') # Remove encapsulataion. Recognizes (, [, { and < as (), [], {} and <>.
|
147
|
+
# => 'example'
|
148
|
+
|
149
|
+
# Roman numerals
|
150
|
+
'Quake III'.from_roman # Converts roman numerals in a string to integers
|
151
|
+
# => 'Quake 3'
|
152
|
+
'Fallout 4'.to_roman # Converts integers in a string to roman numerals
|
153
|
+
# => 'Fallout IV'
|
154
|
+
5.to_roman # Also available directly on Integers.
|
155
|
+
# => 'V'
|
156
|
+
|
157
|
+
# String fuzzy matching
|
158
|
+
'Ruby'.levenshtein_similarity('Rails') # Basic implementation of the Levenshtein distance algorithm. Returns the percentage match. levenshtein_distance is also availabe and returns the computed distance.
|
159
|
+
# => 20.0
|
160
|
+
'Ruby'.composition_similarity('Rails') # Returns the % of characters that are the same between two strings. The number of occurences is also checked for each character.
|
161
|
+
# => 20.0
|
162
|
+
'Sinatra is Elegant'.phrase_similarity('Ruby is Fun') # Returns the amount of words that match between two strings as a percentage.
|
163
|
+
# => 33.333333333
|
164
|
+
|
165
|
+
```
|
166
|
+
|
167
|
+
### FuzzyMatcher
|
168
|
+
|
169
|
+
BBLib::FuzzyMatcher is a class that utilizes the string comparison algorithms shown above as well as the string normalization methods show (convert roman numerals, move articles, etc...) to compare strings. It is most useful for comparing titles or for basic searching.
|
170
|
+
|
171
|
+
There are 4 algorithms that can be used for matching:
|
172
|
+
- levenshtein
|
173
|
+
- composition
|
174
|
+
- numeric
|
175
|
+
- phrase
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
fm = BBLib::FuzzyMatcher.new(
|
179
|
+
case_sensitive: false,
|
180
|
+
convert_roman: true,
|
181
|
+
move_articles: true,
|
182
|
+
remove_symbols: true
|
183
|
+
)
|
184
|
+
|
185
|
+
fm.similarity('Learn Ruby', 'Learn Java') # Returns the percentage of similarity between two strings
|
186
|
+
# => 60.0
|
187
|
+
fm.threshold = 60 # Sets a threshold to match for certain methods (like match?)
|
188
|
+
fm.match?('Elixir', 'C++') # True if two strings have a match percent equal to or greater than the threshold.
|
189
|
+
# => false
|
190
|
+
fm.match?('Elixir', 'Elixr')
|
191
|
+
# => true
|
192
|
+
fm.best_match('Ruby', 'Elixir', 'JRUBY', 'Java', 'C++') # Find the best match amongst an Array for the first argument.
|
193
|
+
# => 'JRUBY'
|
194
|
+
fm.similarities('Ruby', 'Elixir', 'JRUBY', 'Java', 'C++') # Return a hash with how similar an array of words are (by %)
|
195
|
+
# => {"Elixir"=>5.5555555555555545, "JRUBY"=>80.0, "Java"=>0.0, "C++"=>0.0}
|
196
|
+
```
|
197
|
+
|
198
|
+
By default, levenshtein and composition are used, and levenshtein is weighted at 10, while composition is 5. The other algorithms can be turned on, or have their weights adjusted using the set_weight method. A weight of 0 is effectively turning off that algorithm. Any other value is arbitrary, but determines how much the match % of that algorithm affects the global match %.
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
fm.set_weight(:numeric, 5) # Set numeric to a weight of 5
|
202
|
+
fm.set_weight(:composition, 0) # Turn composition off
|
203
|
+
```
|
204
|
+
|
205
|
+
### File
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
# Scan a directory for files using filters. Can be toggled to be recursive.
|
209
|
+
# Filters can be strings or regular expressions. If the string contains an *
|
210
|
+
# it will be treated as a .* in a regexp.
|
211
|
+
# If a block is not passed, this will return an array of strings (paths)
|
212
|
+
BBLib.scan_dir('/var/logs', '*.log', /\.txt/, recursive: true) do |file|
|
213
|
+
# Do something with file...
|
214
|
+
end
|
215
|
+
|
216
|
+
BBLib.scan_files # Same as above, but only matches files (not directories)
|
217
|
+
BBLib.scan_dirs # Matches only directories, files are ignored
|
218
|
+
|
219
|
+
# Simple string to file method
|
220
|
+
# This is a convenience method that uses File.write but can also generate the path to the file if it does not already exist.
|
221
|
+
# It can be called directly on a string or by BBLib.string_to_file(str, path, opts = {})
|
222
|
+
'I want this on disk'.to_file('/opt/my_path/test.txt', mode: 'a') # Write a string to disk
|
223
|
+
|
224
|
+
# Parsing file sizes from strings
|
225
|
+
'1MB 156 kB'.parse_file_size # Parse file size from a string (cumulative). By default this will return the size in bytes.
|
226
|
+
# => 1208320.0
|
227
|
+
# Adjust the output to be in megabytes
|
228
|
+
# Other options are :byte, :kilobyte, :megabyte, :gigabyte, :terabyte, :petabyte, :exabyte, :zettabyte, :yottabyte
|
229
|
+
'1MB 156 kB'.parse_file_size(output: :megabyte)
|
230
|
+
# => 1.15234375
|
231
|
+
'The file size is 19.5 megabytes. Proceed?'.parse_file_size # Can parse from the middle of a string
|
232
|
+
# => 20447232.0
|
233
|
+
```
|
234
|
+
|
235
|
+
## Development
|
236
|
+
|
237
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
238
|
+
|
239
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
240
|
+
|
241
|
+
## Contributing
|
242
|
+
|
243
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bblack16/bblib. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
244
|
+
|
245
|
+
## License
|
246
|
+
|
247
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|