bocadillo 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 511ca3c5532cc2753317809342c469d5a9a427d7
4
+ data.tar.gz: eba82f473f1cae5d3dca6d8dcf10a7cd7fe2da88
5
+ SHA512:
6
+ metadata.gz: dae9ca582edf5025b3d216b380d7a35fe365eefc2e614cc9d3014b2a36ad7e705b9ecdfd2a482b1a5cf4c0e46e571bafc0a63e5bfec0e34ead50b4a3fe60cd3b
7
+ data.tar.gz: b5aa4a0408e9bd7a90eb147cc40a766c4c120fd841d2cd70a4a5080dfc8b062f7984969e9d35436e54f62f16c42ccf0228f7750f84e2e4b1ff639d48aed9a625
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2017, Claudio Procida
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,41 @@
1
+ [![Build Status](https://travis-ci.org/emeraldion/bocadillo.svg?branch=master)](https://travis-ci.org/emeraldion/bocadillo)
2
+
3
+ # bocadillo
4
+
5
+ Converts a list of strings into a compact, readable representation with delimiters of choice
6
+
7
+ ```
8
+ bocadillo 'alba,albero,albergo,alberto'
9
+ # => alb(a|er(go|o|to))
10
+
11
+ bocadillo 'aria:arianna' ':' '[' '+' ']'
12
+ # => aria[+nna]
13
+ ```
14
+
15
+ ## What?
16
+
17
+ In Spanish, [bocadillo](https://es.wiktionary.org/wiki/bocadillo) means sandwich. The name hints at the strings being sliced and interleaved with bread, the delimiters. Bocadillo is the Ruby port of the PHP package [Tramezzino](https://packagist.org/packages/emeraldion/tramezzino).
18
+
19
+ ## Why?
20
+
21
+ Useful when you need to pass long lists of URL params
22
+
23
+ ## Ruby Gem
24
+
25
+ Add it to your Ruby project as a [Ruby Gem](https://rubygems.org):
26
+
27
+ ```sh
28
+ gem install bocadillo
29
+ ```
30
+
31
+ Then have it your way:
32
+
33
+ ```ruby
34
+
35
+ ```
36
+
37
+ ## License
38
+
39
+ Copyright (c) 2017, Claudio Procida
40
+
41
+ [MIT](https://opensource.org/licenses/MIT)
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bocadillo'
4
+
5
+ if (ARGV.length < 1)
6
+ Bocadillo::Usage.print
7
+ exit 1
8
+ end
9
+
10
+ args = Bocadillo::Args.get
11
+ arr = args[:string].split(args[:separator])
12
+ puts Bocadillo.encode(arr, args[:preamble], args[:delimiter], args[:terminator])
@@ -0,0 +1,19 @@
1
+ class Bocadillo
2
+ def self.encode(arr, preamble = '(', divider = '|', terminator = ')')
3
+ arr.sort!
4
+ Serializer.serialize({
5
+ 'l' => '',
6
+ 'c' => Cover.cover(arr)
7
+ }, preamble, divider, terminator)
8
+ end
9
+
10
+ def self.decode(str, preamble = '(', divider = '|', terminator = ')')
11
+ Parser.parse(str, preamble, divider, terminator)
12
+ end
13
+ end
14
+
15
+ require 'bocadillo/args'
16
+ require 'bocadillo/cover'
17
+ require 'bocadillo/parser'
18
+ require 'bocadillo/serializer'
19
+ require 'bocadillo/usage'
@@ -0,0 +1,18 @@
1
+ class Bocadillo::Args
2
+ def self.get
3
+ i = -1
4
+ str = ARGV[i+=1]
5
+ separator = ARGV[i+=1] || ','
6
+ preamble = ARGV[i+=1] || '('
7
+ delimiter = ARGV[i+=1] || '|'
8
+ terminator = ARGV[i+=1] || ')'
9
+
10
+ {
11
+ :string => str,
12
+ :separator => separator,
13
+ :preamble => preamble,
14
+ :delimiter => delimiter,
15
+ :terminator => terminator
16
+ }
17
+ end
18
+ end
@@ -0,0 +1,52 @@
1
+ class Bocadillo::Cover
2
+ def self.cover(arr = [], x0 = 0, y = 0, l = nil)
3
+ l = arr.length if l.nil?
4
+ # Check bad input
5
+ if x0 >= l
6
+ # Error: past assigned slice
7
+ return false
8
+ end
9
+ if x0 > arr.length - 1
10
+ # Error: past array length
11
+ return false;
12
+ end
13
+
14
+ if y > arr[x0].length - 1
15
+ if x0 === l - 1
16
+ # Termination of rightmost string
17
+ return [nil]
18
+ end
19
+ # The string at x0 was only as long as y0, so call on the next item
20
+ return [nil].concat(self.cover(arr, x0 + 1, y, l))
21
+ end
22
+
23
+ # Initialize non-trivial return structure
24
+ u = {
25
+ 'l' => arr[x0][y],
26
+ 'c' => []
27
+ }
28
+ r = [u]
29
+
30
+ # Spread in width until we find either the end, or a different char
31
+ x = x0
32
+ loop do
33
+ m = false
34
+ if x < l && arr[x0][y] === arr[x][y]
35
+ m = true
36
+ x += 1
37
+ end
38
+ break unless m
39
+ end
40
+
41
+ # If we haven't covered the full length of the assigned slice, launch
42
+ # on the pair (x + 1, y0) with the original length l.
43
+ if x < l
44
+ r.concat(self.cover(arr, x, y, l))
45
+ end
46
+
47
+ # Launch on the tail of the string at s[x0] from the position y
48
+ u['c'].concat(self.cover(arr, x0, y + 1, x))
49
+
50
+ r
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+ class Bocadillo::Parser
2
+ def self.parse(str, preamble, divider, terminator)
3
+ arr = []
4
+ i = 0
5
+ j = 0
6
+ k = 0
7
+
8
+ while i < str.length do
9
+ if str[i, str.length].index(preamble) === 0 # (
10
+ t = arr[j + k]
11
+ arr.insert(j + k + 1, t)
12
+ i += preamble.length
13
+ elsif str[i, str.length].index(divider) === 0 # |
14
+ k += 1
15
+ t = arr[j + k]
16
+ arr.insert(j + k, t)
17
+ i += divider.length
18
+ elsif str[i, str.length].index(terminator) === 0 # )
19
+ arr.slice!(j + k + 1, 1)
20
+ j += k
21
+ k = 0
22
+ i += terminator.length
23
+ else
24
+ # trivial case, just keep appending to i+j-th string
25
+ arr[j + k] = (arr[j + k]||'') + str[i]
26
+ i += 1
27
+ end
28
+ end
29
+ arr
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ class Bocadillo::Serializer
2
+ def self.serialize(tree, preamble, divider, terminator, nested = false)
3
+ return '' if tree.nil?
4
+
5
+ head = [tree['l']]
6
+ if tree['c'].length === 0
7
+ return head
8
+ end
9
+
10
+ if tree['c'].length === 1
11
+ tail = [self.serialize(tree['c'][0], preamble, divider, terminator, true)]
12
+ else
13
+ suffixes = tree['c'].map do |suffix|
14
+ Bocadillo::Serializer.serialize(suffix, preamble, divider, terminator, true)
15
+ end
16
+ tail = [suffixes.join(divider)]
17
+ if nested
18
+ tail = [preamble].concat(tail).concat([terminator]);
19
+ end
20
+ end
21
+ return head.concat(tail).join('')
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ class Bocadillo::Usage
2
+ def self.print
3
+ puts <<END
4
+ Usage:
5
+ bocadillo <string> [<separator> [<child preamble> [<child separator> [<child terminator>]]]]
6
+
7
+ Examples:
8
+ bocadillo 'alba,albero,albino'
9
+ # => alb(a|ero|ino)
10
+
11
+ bocadillo 'alba:albero:albino' ':' '[' ',' ']'
12
+ # => alb[a,ero,ino]
13
+
14
+ END
15
+ end
16
+ end
@@ -0,0 +1,103 @@
1
+ require 'test/unit'
2
+ require 'bocadillo'
3
+ require 'yaml'
4
+
5
+ class BocadilloTest < Test::Unit::TestCase
6
+ def setup
7
+ @fixture_file = 'test/fixtures/arrays.yml'
8
+ @fixtures = YAML.load_file(@fixture_file)
9
+ end
10
+
11
+ def test_encode
12
+ # It should return the string unaltered if the array has a single element
13
+ assert_equal 'albero',
14
+ Bocadillo.encode(['albero'], '(', '|', ')')
15
+ end
16
+
17
+ def test_encode_no_common_radix
18
+ # Strings without a common radix
19
+ assert_equal 'a|b|c',
20
+ Bocadillo.encode(['a', 'b', 'c'], '(', '|', ')')
21
+ assert_equal 'albero|fiore',
22
+ Bocadillo.encode(@fixtures['ALBERO_FIORE'], '(', '|', ')')
23
+ end
24
+
25
+ def test_encode_common_radix
26
+ # Strings with a common radix
27
+ assert_equal 'alb(a|er(go|o|to))',
28
+ Bocadillo.encode(@fixtures['ALB_A_ER_GO_O_TO'], '(', '|', ')')
29
+ assert_equal 'pesc(a(|tore)|h(eria|iera))',
30
+ Bocadillo.encode(@fixtures['PESCA_TORE_H_ERIA_IERA'], '(', '|', ')')
31
+ assert_equal 'mar(e|i(a|na(|io)|o))',
32
+ Bocadillo.encode(@fixtures['MARE_INA_IO_IA'], '(', '|', ')')
33
+ end
34
+
35
+ def test_encode_mixed_strings
36
+ # Mixed strings
37
+ assert_equal 'alb(a|er(go|o|to))|pesc(a(|tore)|h(eria|iera))',
38
+ Bocadillo.encode(@fixtures['ALB_A_ER_GO_O_TO'].clone.concat(@fixtures['PESCA_TORE_H_ERIA_IERA']), '(', '|', ')')
39
+ end
40
+
41
+ def test_encode_scrambled_order
42
+ # Order of input doesn't matter
43
+ assert_equal Bocadillo.encode(@fixtures['ALBERO_FIORE'].reverse, '(', '|', ')'),
44
+ Bocadillo.encode(@fixtures['ALBERO_FIORE'], '(', '|', ')')
45
+ assert_equal Bocadillo.encode(@fixtures['ALB_A_ER_GO_O_TO'].reverse, '(', '|', ')'),
46
+ Bocadillo.encode(@fixtures['ALB_A_ER_GO_O_TO'], '(', '|', ')')
47
+ end
48
+
49
+ def test_encode_isin
50
+ @fixture_file = 'test/fixtures/parser.yml'
51
+ @fixtures = YAML.load_file(@fixture_file)
52
+
53
+ # A real life example
54
+ assert_equal @fixtures['ISIN']['string'], Bocadillo.encode(@fixtures['ISIN']['array'], '(', '|', ')')
55
+ end
56
+
57
+ def test_decode
58
+ # It should return the string unaltered if the array has a single element
59
+ assert_equal ['albero'],
60
+ Bocadillo.decode('albero', '(', '|', ')')
61
+ end
62
+
63
+ def test_decode_no_common_radix
64
+ # Strings without a common radix
65
+ assert_equal ['a', 'b', 'c'],
66
+ Bocadillo.decode('a|b|c', '(', '|', ')')
67
+ assert_equal @fixtures['ALBERO_FIORE'],
68
+ Bocadillo.decode('albero|fiore', '(', '|', ')')
69
+ end
70
+
71
+ def test_decode_common_radix
72
+ # Strings with a common radix
73
+ assert_equal @fixtures['ALB_A_ER_GO_O_TO'].sort,
74
+ Bocadillo.decode('alb(a|er(go|o|to))', '(', '|', ')')
75
+ assert_equal @fixtures['PESCA_TORE_H_ERIA_IERA'].sort,
76
+ Bocadillo.decode('pesc(a(|tore)|h(eria|iera))', '(', '|', ')')
77
+ assert_equal @fixtures['MARE_INA_IO_IA'].sort,
78
+ Bocadillo.decode('mar(e|i(a|na(|io)|o))', '(', '|', ')')
79
+ end
80
+
81
+ def test_decode_mixed_strings
82
+ # Mixed strings
83
+ assert_equal @fixtures['ALB_A_ER_GO_O_TO'].clone.concat(@fixtures['PESCA_TORE_H_ERIA_IERA']).sort,
84
+ Bocadillo.decode('alb(a|er(go|o|to))|pesc(a(|tore)|h(eria|iera))', '(', '|', ')')
85
+ end
86
+
87
+ def test_decode_scrambled_order
88
+ # Order of input does matter
89
+ assert_not_equal Bocadillo.decode('albero|fiore', '(', '|', ')'),
90
+ Bocadillo.decode('fiore|albero', '(', '|', ')')
91
+ assert_not_equal Bocadillo.decode('alb(er(o|to|go)|a)', '(', '|', ')'),
92
+ Bocadillo.decode('alb(a|er(go|o|to))', '(', '|', ')')
93
+ end
94
+
95
+ def test_decode_isin
96
+ @fixture_file = 'test/fixtures/parser.yml'
97
+ @fixtures = YAML.load_file(@fixture_file)
98
+
99
+ # A real life example
100
+ assert_equal @fixtures['ISIN']['array'],
101
+ Bocadillo.decode(@fixtures['ISIN']['string'], '(', '|', ')')
102
+ end
103
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bocadillo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Claudio Procida
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Converts a list of strings into a compact, readable representation with
14
+ delimiters of choice
15
+ email: claudio.procida@gmail.com
16
+ executables:
17
+ - bocadillo
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE.md
22
+ - README.md
23
+ - Rakefile
24
+ - bin/bocadillo
25
+ - lib/bocadillo.rb
26
+ - lib/bocadillo/args.rb
27
+ - lib/bocadillo/cover.rb
28
+ - lib/bocadillo/parser.rb
29
+ - lib/bocadillo/serializer.rb
30
+ - lib/bocadillo/usage.rb
31
+ - test/test_bocadillo.rb
32
+ homepage: http://rubygems.org/gems/bocadillo
33
+ licenses:
34
+ - MIT
35
+ metadata: {}
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.6.8
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Compacts a list of strings
56
+ test_files:
57
+ - test/test_bocadillo.rb