elliottcable-stringray 2
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/.manifest +5 -0
- data/README.mkdn +41 -0
- data/Rakefile +93 -0
- data/lib/stringray.rb +136 -0
- data/spec/stringray_spec.rb +108 -0
- metadata +73 -0
data/.manifest
ADDED
data/README.mkdn
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
StringRay
|
2
|
+
=========
|
3
|
+
|
4
|
+
**StringRay** exposes a powerful method to split a `String` into an `Array` of words,
|
5
|
+
and further allows you to include `Enumerable`, thus exposing many of the
|
6
|
+
most useful `Array` methods on your `String`s.
|
7
|
+
|
8
|
+
Usage
|
9
|
+
-----
|
10
|
+
|
11
|
+
class String; include StringRay; end
|
12
|
+
|
13
|
+
"Oi! I'm a string, do something fun with me!".each do |word|
|
14
|
+
p word
|
15
|
+
end
|
16
|
+
|
17
|
+
Getting
|
18
|
+
-------
|
19
|
+
|
20
|
+
The authoritative source for this project is available at
|
21
|
+
<http://github.com/elliottcable/stringray>. You can clone your own copy with the
|
22
|
+
following command:
|
23
|
+
|
24
|
+
git clone git://github.com/elliottcable/stringray.git
|
25
|
+
|
26
|
+
If you want to make changes to the codebase, you need to fork your own GitHub
|
27
|
+
repository for said changes. Send a pullrequest to [elliottcable](http://github.com/elliottcable "elliottcable on GitHub")
|
28
|
+
when you've got something ready for the master branch that you think should be
|
29
|
+
merged.
|
30
|
+
|
31
|
+
Requirements
|
32
|
+
------------
|
33
|
+
|
34
|
+
To run git-blog, you need... nothing!
|
35
|
+
|
36
|
+
To develop and contribute to git-blog, you also need:
|
37
|
+
|
38
|
+
* `gem install rake`
|
39
|
+
* `gem install rspec`
|
40
|
+
* `gem install rcov`
|
41
|
+
* `gem install echoe`
|
data/Rakefile
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
($:.unshift File.expand_path(File.join( File.dirname(__FILE__), 'lib' ))).uniq!
|
2
|
+
require 'stringray'
|
3
|
+
require 'extlib/string' # String#/, because I'm a lazy fuck.
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'spec/rake/spectask'
|
7
|
+
require 'spec/rake/verify_rcov'
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'echoe'
|
11
|
+
|
12
|
+
namespace :echoe do
|
13
|
+
Echoe.new('StringRay', StringRay::VERSION) do |g|
|
14
|
+
g.name = 'stringray'
|
15
|
+
g.author = ['elliottcable']
|
16
|
+
g.email = ['StringRay@elliottcable.com']
|
17
|
+
g.summary = 'Combining many of the benefits of Arrays and Strings, StringRay allows you to treat a String as an Array of words in many cases.'
|
18
|
+
g.url = 'http://github.com/elliottcable/stringray'
|
19
|
+
g.dependencies = []
|
20
|
+
g.manifest_name = '.manifest'
|
21
|
+
g.ignore_pattern = ['.git', 'meta', 'stringray.gemspec']
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'tests packaged files to ensure they are all present'
|
25
|
+
task :verify => :package do
|
26
|
+
# An error message will be displayed if files are missing
|
27
|
+
if system %(ruby -e "require 'rubygems'; require 'pkg/merb_strokedb-#{StringRay::VERSION}/lib/stringray'")
|
28
|
+
puts "\nThe library files are present"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
task :copy_gemspec => [:package] do
|
33
|
+
pkg = Dir['pkg/*'].select {|dir| File.directory? dir}.last
|
34
|
+
mv File.join(pkg, pkg.gsub(/^pkg\//,'').gsub(/\-\d+$/,'.gemspec')), './'
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'builds a gemspec as GitHub wants it'
|
38
|
+
task :gemspec => [:package, :copy_gemspec, :clobber_package]
|
39
|
+
|
40
|
+
# desc 'Run specs, clean tree, update manifest, run coverage, and install gem!'
|
41
|
+
desc 'Clean tree, update manifest, and install gem!'
|
42
|
+
task :magic => [:clean, :manifest, :install]
|
43
|
+
end
|
44
|
+
|
45
|
+
task :manifest => [:'echoe:manifest']
|
46
|
+
|
47
|
+
rescue LoadError => boom
|
48
|
+
puts "You are missing a dependency required for meta-operations on this gem."
|
49
|
+
puts "#{boom.to_s.capitalize}."
|
50
|
+
ensure
|
51
|
+
task :default # No effect # Invisible
|
52
|
+
|
53
|
+
# Runs specs, generates rcov, and opens rcov in your browser.
|
54
|
+
namespace :rcov do
|
55
|
+
Spec::Rake::SpecTask.new(:run) do |t|
|
56
|
+
t.spec_opts = ["--format", "specdoc", "--colour"]
|
57
|
+
t.spec_files = Dir['spec/**/*_spec.rb'].sort
|
58
|
+
t.libs = ['lib']
|
59
|
+
t.rcov = true
|
60
|
+
t.rcov_dir = 'meta' / 'coverage'
|
61
|
+
end
|
62
|
+
|
63
|
+
Spec::Rake::SpecTask.new(:plain) do |t|
|
64
|
+
t.spec_opts = ["--format", "specdoc"]
|
65
|
+
t.spec_files = Dir['spec/**/*_spec.rb'].sort
|
66
|
+
t.libs = ['lib']
|
67
|
+
t.rcov = true
|
68
|
+
t.rcov_opts = ['--exclude-only', '".*"', '--include-file', '^lib']
|
69
|
+
t.rcov_dir = 'meta' / 'coverage'
|
70
|
+
end
|
71
|
+
|
72
|
+
RCov::VerifyTask.new(:verify) do |t|
|
73
|
+
t.threshold = 100
|
74
|
+
t.index_html = 'meta' / 'coverage' / 'index.html'
|
75
|
+
end
|
76
|
+
|
77
|
+
task :open do
|
78
|
+
system 'open ' + 'meta' / 'coverage' / 'index.html' if PLATFORM['darwin']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
namespace :git do
|
83
|
+
task :status do
|
84
|
+
`git status`
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
desc 'Check everything over before commiting'
|
89
|
+
task :aok => [:'echoe:manifest', :'rcov:run', :'rcov:verify', :'rcov:ratio', :'rcov:open', :'git:status']
|
90
|
+
|
91
|
+
# desc 'Task run during continuous integration' # Invisible
|
92
|
+
task :cruise => [:'rcov:plain', :'rcov:verify', :'rcov:ratio']
|
93
|
+
end
|
data/lib/stringray.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
module StringRay
|
2
|
+
VERSION = 2
|
3
|
+
|
4
|
+
# Splits a string into words. Not using the obvious names (+#split+, +#words+)
|
5
|
+
# because I want compatibility for inclusion into +String+.
|
6
|
+
def enumerate
|
7
|
+
ray = []
|
8
|
+
|
9
|
+
self.each_byte do |byte|
|
10
|
+
char = byte.chr
|
11
|
+
|
12
|
+
if Delimiter::Characters.include? char
|
13
|
+
ray << Delimiter.new(char)
|
14
|
+
|
15
|
+
elsif Whitespace::Characters.include? char
|
16
|
+
if ray.last.is_a? Whitespace
|
17
|
+
ray.last << char
|
18
|
+
else
|
19
|
+
ray << Whitespace.new(char)
|
20
|
+
end
|
21
|
+
|
22
|
+
else
|
23
|
+
if ray.last.is_a? Word
|
24
|
+
ray.last << char
|
25
|
+
else
|
26
|
+
ray << Word.new(char)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
ray
|
33
|
+
end
|
34
|
+
|
35
|
+
# More sensible than +String#each+, this uses +#enumerate+ to enumerate on
|
36
|
+
# words. Accepts options as a hash, determining whether :whitespace and
|
37
|
+
# :delemiters will :attach_before, :standalone, or :attach_after. Default is
|
38
|
+
# for both to :attach_before.
|
39
|
+
def each_word opts = {}, &block
|
40
|
+
{:whitespace => :attach_before, :delemiters => :attach_before}.merge! opts
|
41
|
+
|
42
|
+
# First, we create a two-dimensional array of words with any whitespace or
|
43
|
+
# delemiters that should attach to them.
|
44
|
+
words = self.enumerate
|
45
|
+
mapped = []
|
46
|
+
attach_before_next = []
|
47
|
+
|
48
|
+
words.each do |item|
|
49
|
+
case item
|
50
|
+
when Delimiter
|
51
|
+
case opts[:delemiters]
|
52
|
+
when :standalone
|
53
|
+
mapped << [item]
|
54
|
+
when :attach_after
|
55
|
+
attach_before_next << item
|
56
|
+
else
|
57
|
+
if attach_before_next.empty?
|
58
|
+
if mapped.last
|
59
|
+
mapped.last << item
|
60
|
+
else
|
61
|
+
attach_before_next << item
|
62
|
+
end
|
63
|
+
else
|
64
|
+
attach_before_next << item
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
when Whitespace
|
69
|
+
case opts[:whitespace]
|
70
|
+
when :standalone
|
71
|
+
mapped << [item]
|
72
|
+
when :attach_after
|
73
|
+
attach_before_next << item
|
74
|
+
else
|
75
|
+
if attach_before_next.empty?
|
76
|
+
if mapped.last
|
77
|
+
mapped.last << item
|
78
|
+
else
|
79
|
+
attach_before_next << item
|
80
|
+
end
|
81
|
+
else
|
82
|
+
attach_before_next << item
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
when Word
|
87
|
+
if not attach_before_next.empty?
|
88
|
+
mapped << [attach_before_next, item].flatten
|
89
|
+
attach_before_next = []
|
90
|
+
else
|
91
|
+
mapped << [item]
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
(mapped.last << attach_before_next).flatten! if not attach_before_next.empty?
|
97
|
+
|
98
|
+
# Next, we yield each group of (word plus delimiters and whitespace) as a
|
99
|
+
# normal string to the block
|
100
|
+
mapped.each do |arr|
|
101
|
+
yield arr.map{|w|w.to_s}.join
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Word < String
|
106
|
+
def inspect
|
107
|
+
"(#{self})"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class Whitespace < String
|
112
|
+
Characters = [" ", "\t", "\n"]
|
113
|
+
def inspect
|
114
|
+
"#{self}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Delimiter < String
|
119
|
+
Characters = ['-', ',', '.', '?', '!', ':', ';', '/', '\\', '|']
|
120
|
+
|
121
|
+
def inspect
|
122
|
+
"<#{self}>"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# This overrides +String#each+ with +StringRay#each_word+, thus allowing us
|
127
|
+
# to include +Enumerable+.
|
128
|
+
def self.included klass
|
129
|
+
klass.class_eval do
|
130
|
+
alias_method :each_at, :each
|
131
|
+
alias_method :each, :each_word
|
132
|
+
|
133
|
+
include Enumerable
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
($:.unshift File.expand_path(File.join( File.dirname(__FILE__), '..', 'lib' ))).uniq!
|
2
|
+
require 'stringray'
|
3
|
+
|
4
|
+
describe 'a String including StringRay' do
|
5
|
+
before :all do
|
6
|
+
String.send :include, StringRay
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#enumerate' do
|
10
|
+
it 'should split a string into an array' do
|
11
|
+
string = 'The time has come to talk of many things - of sailing ' +
|
12
|
+
'ships and sealing wax, of cabbages and kings!'
|
13
|
+
string.inject([]) {|a, i| a << i }.should ==
|
14
|
+
['The ','time ','has ','come ','to ','talk ','of ',
|
15
|
+
'many ','things - ','of ','sailing ','ships ','and ','sealing ',
|
16
|
+
'wax, ','of ','cabbages ','and ','kings!']
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should correctly treat commas and lists' do
|
20
|
+
string = 'I have commas, periods, and other punctuation'
|
21
|
+
string.inject([]) {|a, i| a << i }.should ==
|
22
|
+
['I ','have ','commas, ','periods, ','and ','other ','punctuation']
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should correctly treat periods and end-of-sentance demarcators' do
|
26
|
+
string = 'Periods. Cool right? Yah!'
|
27
|
+
string.inject([]) {|a, i| a << i }.should ==
|
28
|
+
['Periods. ','Cool ','right? ','Yah!']
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should correctly treat dahses' do
|
32
|
+
string = 'I have - uh - dashes!'
|
33
|
+
string.inject([]) {|a, i| a << i }.should ==
|
34
|
+
['I ','have - ','uh - ','dashes!']
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should correctly treat ellipses' do
|
38
|
+
string = 'Where are we... going?'
|
39
|
+
string.inject([]) {|a, i| a << i }.should ==
|
40
|
+
['Where ','are ','we... ','going?']
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should correctly treat a delimated word' do
|
44
|
+
string = 'String and Array, sitting in a tree - K-I-S-S-I-N-G!'
|
45
|
+
string.inject([]) {|a, i| a << i }.should ==
|
46
|
+
['String ','and ','Array, ','sitting ','in ','a ','tree - ','K-','I-','S-','S-','I-','N-','G!']
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should correctly treat inline line returns' do
|
50
|
+
string = "This has\na line return!"
|
51
|
+
string.inject([]) {|a, i| a << i }.should ==
|
52
|
+
["This ","has\n","a ","line ","return!"]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should correctly treat prefacing line returns and whitespace' do
|
56
|
+
string = "\n Now it starts!\n\n"
|
57
|
+
string.inject([]) {|a, i| a << i }.should ==
|
58
|
+
["\n Now ","it ","starts!\n\n"]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#each_word' do
|
63
|
+
it 'should be able to attach delimeters to the beginning of the next word' do
|
64
|
+
string = 'The time has come to talk of many things - of sailing ' +
|
65
|
+
'ships and sealing wax, of cabbages and kings!'
|
66
|
+
array = []
|
67
|
+
string.each(:delemiters => :attach_after) {|i| array << i }
|
68
|
+
array.should == ['The ','time ','has ','come ','to ','talk ','of ',
|
69
|
+
'many ','things ','- of ','sailing ','ships ','and ','sealing ',
|
70
|
+
'wax',', of ','cabbages ','and ','kings!']
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should be able to let delimeters stand alone' do
|
74
|
+
string = 'The time has come to talk of many things - of sailing ' +
|
75
|
+
'ships and sealing wax, of cabbages and kings!'
|
76
|
+
array = []
|
77
|
+
string.each(:delemiters => :standalone) {|i| array << i }
|
78
|
+
array.should == ['The ','time ','has ','come ','to ','talk ','of ',
|
79
|
+
'many ','things ','- ', 'of ','sailing ','ships ','and ','sealing ',
|
80
|
+
'wax',', ','of ','cabbages ','and ','kings','!']
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should be able to attach whitespace to the beginning of the next word' do
|
84
|
+
string = 'The time has come to talk of many things - of sailing ' +
|
85
|
+
'ships and sealing wax, of cabbages and kings!'
|
86
|
+
array = []
|
87
|
+
string.each(:whitespace => :attach_after) {|i| array << i }
|
88
|
+
array.should == ['The',' time',' has',' come',' to',' talk',' of',
|
89
|
+
' many',' things',' - of',' sailing',' ships',' and',' sealing',
|
90
|
+
' wax,',' of',' cabbages',' and',' kings!']
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should be able to let whitespace stand alone' do
|
94
|
+
string = 'The time has come to talk of many things - of sailing ' +
|
95
|
+
'ships and sealing wax, of cabbages and kings!'
|
96
|
+
array = []
|
97
|
+
string.each(:whitespace => :standalone) {|i| array << i }
|
98
|
+
array.should == ['The',' ','time',' ','has',' ','come',' ','to',' ','talk',' ','of',
|
99
|
+
' ','many',' ','things',' -',' ','of',' ','sailing',' ','ships',' ','and',' ','sealing',
|
100
|
+
' ','wax,',' ','of',' ','cabbages',' ','and',' ','kings!']
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# TODO: Figure out a better way to say 'should be_include(Enumerable)'
|
105
|
+
it 'should also include enumerable' do
|
106
|
+
String.ancestors.should be_include(Enumerable)
|
107
|
+
end
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elliottcable-stringray
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "2"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- elliottcable
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
date: 2008-08-12 01:00:00 -07:00
|
12
|
+
default_executable:
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: echoe
|
16
|
+
type: :development
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description: Combining many of the benefits of Arrays and Strings, StringRay allows you to treat a String as an Array of words in many cases.
|
25
|
+
email:
|
26
|
+
- StringRay@elliottcable.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- lib/stringray.rb
|
33
|
+
- README.mkdn
|
34
|
+
files:
|
35
|
+
- lib/stringray.rb
|
36
|
+
- Rakefile
|
37
|
+
- README.mkdn
|
38
|
+
- spec/stringray_spec.rb
|
39
|
+
- .manifest
|
40
|
+
- StringRay.gemspec
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/elliottcable/stringray
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --line-numbers
|
46
|
+
- --inline-source
|
47
|
+
- --title
|
48
|
+
- StringRay
|
49
|
+
- --main
|
50
|
+
- README.mkdn
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "1.2"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: stringray
|
68
|
+
rubygems_version: 1.2.0
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: Combining many of the benefits of Arrays and Strings, StringRay allows you to treat a String as an Array of words in many cases.
|
72
|
+
test_files: []
|
73
|
+
|