fugu 0.8.0
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.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +70 -0
- data/VERSION +1 -0
- data/bin/fugu +29 -0
- data/features/puff.feature +70 -0
- data/features/shrink.feature +38 -0
- data/features/step_definitions/fugu_steps.rb +46 -0
- data/features/support/env.rb +7 -0
- data/lib/array.rb +21 -0
- data/lib/fugu.rb +70 -0
- data/test/fugu_test.rb +19 -0
- data/test/test_helper.rb +10 -0
- metadata +90 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Erik Kastner, Ian Meyer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= fugu
|
2
|
+
|
3
|
+
A magical string puffer and shrinker.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but
|
13
|
+
bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Erik Kastner and Ian Meyer. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "fugu"
|
8
|
+
gem.summary = %Q{Magically puff or shrink strings}
|
9
|
+
gem.description = %Q{Puff: host0{9-10} to host09 host10}
|
10
|
+
gem.email = "kastner@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/kastner/fugu"
|
12
|
+
gem.authors = ["Erik Kastner"]
|
13
|
+
gem.add_development_dependency "shoulda"
|
14
|
+
gem.add_development_dependency "cucumber"
|
15
|
+
gem.executables = ['fugu']
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'rake/testtask'
|
24
|
+
Rake::TestTask.new(:test) do |test|
|
25
|
+
test.libs << 'lib' << 'test'
|
26
|
+
test.pattern = 'test/**/*_test.rb'
|
27
|
+
test.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
begin
|
31
|
+
require 'rcov/rcovtask'
|
32
|
+
Rcov::RcovTask.new do |test|
|
33
|
+
test.libs << 'test'
|
34
|
+
test.pattern = 'test/**/*_test.rb'
|
35
|
+
test.verbose = true
|
36
|
+
end
|
37
|
+
rescue LoadError
|
38
|
+
task :rcov do
|
39
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
task :test => :check_dependencies
|
44
|
+
|
45
|
+
begin
|
46
|
+
require 'cucumber/rake/task'
|
47
|
+
Cucumber::Rake::Task.new(:features)
|
48
|
+
|
49
|
+
task :features => :check_dependencies
|
50
|
+
rescue LoadError
|
51
|
+
task :features do
|
52
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
task :default => :test
|
57
|
+
|
58
|
+
require 'rake/rdoctask'
|
59
|
+
Rake::RDocTask.new do |rdoc|
|
60
|
+
if File.exist?('VERSION')
|
61
|
+
version = File.read('VERSION')
|
62
|
+
else
|
63
|
+
version = ""
|
64
|
+
end
|
65
|
+
|
66
|
+
rdoc.rdoc_dir = 'rdoc'
|
67
|
+
rdoc.title = "fugu #{version}"
|
68
|
+
rdoc.rdoc_files.include('README*')
|
69
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
70
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.8.0
|
data/bin/fugu
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
|
5
|
+
%w{rubygems fugu optparse}.each { |m| require m }
|
6
|
+
|
7
|
+
options = {}
|
8
|
+
OptionParser.new() do |opts|
|
9
|
+
opts.banner = "Usage: #{$0} RANGE"
|
10
|
+
|
11
|
+
options[:action] = "puff"
|
12
|
+
opts.on('-s', '--shrink', 'Shrink expression') do
|
13
|
+
options[:action] = "shrink"
|
14
|
+
end
|
15
|
+
|
16
|
+
options[:delimiter] = "\n"
|
17
|
+
opts.on('-d', '--delimiter DELIMITER', String, 'Delimiter') do |delimiter|
|
18
|
+
options[:delimiter] = delimiter
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.parse!
|
22
|
+
end
|
23
|
+
|
24
|
+
string = ARGV[0] || ARGF.read
|
25
|
+
|
26
|
+
puts case options[:action]
|
27
|
+
when "puff" then Fugu.puff(string).join(options[:delimiter])
|
28
|
+
when "shrink" then Fugu.shrink(string, options[:delimiter])
|
29
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
Feature: Puffing up
|
2
|
+
In order to puff some text
|
3
|
+
A user passes input to fugu
|
4
|
+
And gets something useful out
|
5
|
+
|
6
|
+
Scenario: Unexpandable text should come back as it went in
|
7
|
+
Given the string "web0001" and delimiter ","
|
8
|
+
When I puff it
|
9
|
+
Then I should get back "web0001"
|
10
|
+
And @text should be "web0001"
|
11
|
+
|
12
|
+
Scenario: Unexpandable Fugu expression comes back as it went in
|
13
|
+
Given the string "web{0001}" and delimiter ","
|
14
|
+
When I puff it
|
15
|
+
Then I should get back "web0001"
|
16
|
+
And @text should be "web{0001}"
|
17
|
+
|
18
|
+
Scenario: Simple expansion
|
19
|
+
Given the string "web000{1,2}" and delimiter ","
|
20
|
+
When I puff it
|
21
|
+
Then I should get back "web0001,web0002"
|
22
|
+
|
23
|
+
Scenario: Range expanstion
|
24
|
+
Given the string "web000{1-3}" and delimiter ","
|
25
|
+
When I puff it
|
26
|
+
Then I should get back "web0001,web0002,web0003"
|
27
|
+
|
28
|
+
Scenario: Simple Range expanstion
|
29
|
+
Given the string "web{1-2}" and delimiter ","
|
30
|
+
When I puff it
|
31
|
+
Then I should get back "web1,web2"
|
32
|
+
|
33
|
+
Scenario: Mix of simple and complex ranges
|
34
|
+
Given the string "web000{1,2-4,6}" and delimiter ","
|
35
|
+
When I puff it
|
36
|
+
Then I should get back "web0001,web0002,web0003,web0004,web0006"
|
37
|
+
|
38
|
+
Scenario: Simple two range expansion
|
39
|
+
Given the string "web0001|api01" and delimiter ","
|
40
|
+
When I puff it
|
41
|
+
Then I should get back "web0001,api01"
|
42
|
+
|
43
|
+
Scenario: Complex two range expansion
|
44
|
+
Given the string "web000{1-3}|api0{1-2}" and delimiter ","
|
45
|
+
When I puff it
|
46
|
+
Then I should get back "web0001,web0002,web0003,api01,api02"
|
47
|
+
|
48
|
+
Scenario: Doing a permanent expansion
|
49
|
+
Given the string "web000{1-3}" and delimiter ","
|
50
|
+
When I really puff it
|
51
|
+
Then @text should be "web0001,web0002,web0003"
|
52
|
+
|
53
|
+
Scenario: Expansion with zeros
|
54
|
+
Given the string "web{09-12}" and delimiter ","
|
55
|
+
When I puff it
|
56
|
+
Then I should get back "web09,web10,web11,web12"
|
57
|
+
|
58
|
+
Scenario: Class method puff
|
59
|
+
When I call puff on Fugu with "web000{1-3}"
|
60
|
+
Then I should have "web0001,web0002,web0003"
|
61
|
+
|
62
|
+
Scenario: Puffing unpadded string always returns correct pad amount
|
63
|
+
Given the string "web00{9-10}" and delimiter ","
|
64
|
+
When I puff it
|
65
|
+
Then I should get back "web0009,web0010"
|
66
|
+
|
67
|
+
#Scenario: Removing entry from puffed string
|
68
|
+
# Given the string "web00{9-11} - web0010" and delimiter ","
|
69
|
+
# When I puff it
|
70
|
+
# Then I should get back "web0009,web0011"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Feature: Shrinking down
|
2
|
+
In order to shrink some text
|
3
|
+
A user passes input to fugu
|
4
|
+
And gets a shorter version (if possible)
|
5
|
+
|
6
|
+
Scenario: Simplest shrink
|
7
|
+
Given the string "web1,web2" and delimiter ","
|
8
|
+
When I shrink it
|
9
|
+
Then I should get the string "web{1-2}"
|
10
|
+
|
11
|
+
Scenario: Longer range shrink
|
12
|
+
Given the string "web1,web2,web3" and delimiter ","
|
13
|
+
When I shrink it
|
14
|
+
Then I should get the string "web{1-3}"
|
15
|
+
|
16
|
+
Scenario: Range with gap shrink
|
17
|
+
Given the string "web1,web2,web4" and delimiter ","
|
18
|
+
When I shrink it
|
19
|
+
Then I should get the string "web{1-2,4}"
|
20
|
+
|
21
|
+
Scenario: Range, gap, range, gap...
|
22
|
+
Given the string "web1,web2,web9,web6,web7,web4" and delimiter ","
|
23
|
+
When I shrink it
|
24
|
+
Then I should get the string "web{1-2,4,6-7,9}"
|
25
|
+
|
26
|
+
Scenario: zeros...
|
27
|
+
Given the string "web01,web02,web12,web13,web14,web15" and delimiter ","
|
28
|
+
When I shrink it
|
29
|
+
Then I should get the string "web{01-02,12-15}"
|
30
|
+
|
31
|
+
Scenario: Class method of shrink
|
32
|
+
When I call shrink on Fugu with "web001,web002,web003" and delimiter ","
|
33
|
+
Then I should have shrunk "web00{1-3}"
|
34
|
+
|
35
|
+
#Scenario: Multiple shrinks
|
36
|
+
# Given the string "web1,web2,api3,api4" and delimiter ","
|
37
|
+
# When I shrink it
|
38
|
+
# Then I should get the string "web{1-2}|api{3-4}"
|
@@ -0,0 +1,46 @@
|
|
1
|
+
Given /^the string "([^\"]*)" and delimiter "([^\"]*)"$/ do |arg1, arg2|
|
2
|
+
@f = Fugu.new
|
3
|
+
@f.text = arg1
|
4
|
+
@f.delimiter = arg2
|
5
|
+
end
|
6
|
+
|
7
|
+
When /^I puff it$/ do
|
8
|
+
@message = "puff"
|
9
|
+
end
|
10
|
+
|
11
|
+
When /^I shrink it$/ do
|
12
|
+
@message = "shrink"
|
13
|
+
end
|
14
|
+
|
15
|
+
Then /^I should get back "([^\"]*)"$/ do |arg1|
|
16
|
+
assert_equal arg1, @f.send(@message).join(",")
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^I should get the string "([^\"]*)"$/ do |arg1|
|
20
|
+
assert_equal arg1, @f.send(@message)
|
21
|
+
end
|
22
|
+
|
23
|
+
When /^I really puff it$/ do
|
24
|
+
@f.puff!
|
25
|
+
end
|
26
|
+
|
27
|
+
Then /^@text should be "([^\"]*)"$/ do |arg1|
|
28
|
+
# assert_equal arg1, @f.send().join(',')
|
29
|
+
end
|
30
|
+
|
31
|
+
When /^I call puff on Fugu with "([^\"]*)"$/ do |arg1|
|
32
|
+
@string = arg1
|
33
|
+
end
|
34
|
+
|
35
|
+
Then /^I should have "([^\"]*)"$/ do |arg1|
|
36
|
+
assert_equal arg1, Fugu.puff(@string).join(',')
|
37
|
+
end
|
38
|
+
|
39
|
+
When /^I call shrink on Fugu with "([^\"]*)" and delimiter "([^\"]*)"$/ do |arg1, arg2|
|
40
|
+
@string = arg1
|
41
|
+
@delimiter = arg2
|
42
|
+
end
|
43
|
+
|
44
|
+
Then /^I should have shrunk "([^\"]*)"$/ do |arg1|
|
45
|
+
assert_equal arg1, Fugu.shrink(@string, @delimiter)
|
46
|
+
end
|
data/lib/array.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class Array
|
2
|
+
def to_ranges
|
3
|
+
array = self.compact.uniq.sort
|
4
|
+
ranges = []
|
5
|
+
if !array.empty?
|
6
|
+
# Initialize the left and right endpoints of the range
|
7
|
+
left, right = self.first, nil
|
8
|
+
array.each do |obj|
|
9
|
+
# If the right endpoint is set and obj is not equal to right's successor
|
10
|
+
# then we need to create a range.
|
11
|
+
if right && obj != right.succ
|
12
|
+
ranges << Range.new(left,right)
|
13
|
+
left = obj
|
14
|
+
end
|
15
|
+
right = obj
|
16
|
+
end
|
17
|
+
ranges << Range.new(left,right)
|
18
|
+
end
|
19
|
+
ranges
|
20
|
+
end
|
21
|
+
end
|
data/lib/fugu.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'array'
|
2
|
+
|
3
|
+
class Fugu
|
4
|
+
attr_accessor :text, :delimiter
|
5
|
+
|
6
|
+
def self.puff(string)
|
7
|
+
f = self.new
|
8
|
+
f.text = string
|
9
|
+
f.puff
|
10
|
+
end
|
11
|
+
|
12
|
+
def puff
|
13
|
+
@text.split('|').collect do |range|
|
14
|
+
if range.match(/\{/)
|
15
|
+
before, expand_string, after = range.scan(/(.*)\{(.*)\}(.*)/)[0]
|
16
|
+
expanded_string = puff_expression(expand_string)
|
17
|
+
range = expanded_string.map { |piece| before + piece + after }
|
18
|
+
end
|
19
|
+
range
|
20
|
+
end.flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
def puff!
|
24
|
+
@text = puff
|
25
|
+
end
|
26
|
+
|
27
|
+
def puff_expression(string)
|
28
|
+
string.split(",").collect do |v|
|
29
|
+
(v[/-/]) ? Range.new(*pad_expression(v).split('-')).to_a : v
|
30
|
+
end.flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.shrink(string, delimiter)
|
34
|
+
f = self.new
|
35
|
+
f.text = string
|
36
|
+
f.delimiter = delimiter
|
37
|
+
f.shrink
|
38
|
+
end
|
39
|
+
|
40
|
+
def shrink
|
41
|
+
pieces = @text.split("#{@delimiter}")
|
42
|
+
first, base = pieces.first, pieces.first
|
43
|
+
first.size.times do |len|
|
44
|
+
base = first[0, first.size-len]
|
45
|
+
break if pieces.all? {|p| p.match(base)}
|
46
|
+
end
|
47
|
+
diffs = pieces.map {|p| (p.scan(/./) - base.scan(/./)).join}
|
48
|
+
base + "{#{shrink_array(diffs)}}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def shrink!
|
52
|
+
@text = shrink
|
53
|
+
end
|
54
|
+
|
55
|
+
def shrink_array(array)
|
56
|
+
array.flatten.to_ranges.map do |r|
|
57
|
+
if r.first == r.last
|
58
|
+
r.first
|
59
|
+
else
|
60
|
+
"#{r.first}-#{r.last}"
|
61
|
+
end
|
62
|
+
end.join(",")
|
63
|
+
end
|
64
|
+
|
65
|
+
def pad_expression(string)
|
66
|
+
fat = string.split('-')
|
67
|
+
"%0#{fat.last.length}d-#{fat.last}" % fat.first.to_i
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
data/test/fugu_test.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FuguTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@fugu = Fugu.new
|
6
|
+
end
|
7
|
+
|
8
|
+
should "puff a string like {1-3}" do
|
9
|
+
assert_equal %w[1 2 3], @fugu.puff_expression("1-3")
|
10
|
+
end
|
11
|
+
|
12
|
+
should "shrink a string like 1,2,3" do
|
13
|
+
assert_equal "1-3", @fugu.shrink_array(%w[1 2 3])
|
14
|
+
end
|
15
|
+
|
16
|
+
should "pad expression with appropriate number of zeros" do
|
17
|
+
assert_equal "01-10", @fugu.pad_expression("1-10")
|
18
|
+
end
|
19
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fugu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erik Kastner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-07 00:00:00 -05:00
|
13
|
+
default_executable: fugu
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cucumber
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: "Puff: host0{9-10} to host09 host10"
|
36
|
+
email: kastner@gmail.com
|
37
|
+
executables:
|
38
|
+
- fugu
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- bin/fugu
|
52
|
+
- features/puff.feature
|
53
|
+
- features/shrink.feature
|
54
|
+
- features/step_definitions/fugu_steps.rb
|
55
|
+
- features/support/env.rb
|
56
|
+
- lib/array.rb
|
57
|
+
- lib/fugu.rb
|
58
|
+
- test/fugu_test.rb
|
59
|
+
- test/test_helper.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/kastner/fugu
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --charset=UTF-8
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.5
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Magically puff or shrink strings
|
88
|
+
test_files:
|
89
|
+
- test/fugu_test.rb
|
90
|
+
- test/test_helper.rb
|