superstring 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - ree
7
+
8
+ script: "bundle exec rspec --color --format nested"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in superstring.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Harlan T Wood
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ SuperString [![Build Status](https://travis-ci.org/harlantwood/superstring.png?branch=master)](https://travis-ci.org/harlantwood/superstring)
2
+ ===========
3
+
4
+ Grant superpowers to instances of the Ruby String class.
5
+
6
+ Split stings into sentences, convert to URL-friendly slugs, generate hashcodes, and more...
7
+
8
+ Basic Usage
9
+ -----------
10
+
11
+ Install or bundle gem. Then, simply:
12
+
13
+ require 'superstring'
14
+
15
+ This will add new methods to the basic Ruby String class, which are described below.
16
+
17
+ Slug generation
18
+ ---------------
19
+
20
+ **Slugs safe for file names, and (arguably) URLs**
21
+
22
+ "Les Misérables".slug(:page)
23
+ => "Les-Misérables"
24
+
25
+ `:page` is the default style, so this argument can be omitted:
26
+
27
+ "Les Misérables".slug
28
+ => "Les-Misérables"
29
+
30
+ **Slugs safe for subdomains**
31
+
32
+ "Les Misérables".slug(:subdomain)
33
+ => "les-miserables"
34
+
35
+ **Slugs safe for subdomains, padded with random digits to meet a given minimum length**
36
+
37
+ "Les Misérables".slug(:padded_subdomain, 20)
38
+ => "les-miserables-62858"
39
+
40
+ Extract domain name from URI
41
+ ----------------------------
42
+
43
+ "http://www.mediawiki.org/wiki/Manual:$wgUrlProtocols".domain
44
+ => "mediawiki.org"
45
+
46
+ Sentences
47
+ ---------
48
+
49
+ paragraph = "That that is, is. That that is not, is not. That is it, is it not?"
50
+ paragraph.sentences
51
+ => ["That that is, is.", "That that is not, is not.", "That is it, is it not?"]
52
+
53
+ poem = paragraph.sentence_poem
54
+ => "That that is, is.\nThat that is not, is not.\nThat is it, is it not?"
55
+ puts poem
56
+ That that is, is.
57
+ That that is not, is not.
58
+ That is it, is it not?
59
+
60
+ SHA1 - SHA512 methods
61
+ ---------------------
62
+
63
+ "The quick brown fox jumps over the lazy dog".sha1
64
+ => "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
65
+ "The quick brown fox jumps over the lazy dog".sha256
66
+ => "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"
67
+ "The quick brown fox jumps over the lazy dog".sha384
68
+ => "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1"
69
+ "The quick brown fox jumps over the lazy dog".sha512
70
+ => "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"
71
+
72
+ Whitespace
73
+ ----------
74
+
75
+ " foo \r\n bar ".compact_whitespace
76
+ => "foo bar"
77
+ " foo \r\n bar ".strip_lines!
78
+ => "foo\r\nbar"
79
+
80
+ Check for inclusion in a given collection
81
+ -----------------------------------------
82
+
83
+ collection = ["foo", "bar"]
84
+ => ["foo", "bar"]
85
+ "foo".in? collection
86
+ => true
87
+ "food".in? collection
88
+ => false
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,10 @@
1
+ module Gollum
2
+ class Page
3
+ unless Page.respond_to?(:cname)
4
+ def self.cname(name, char_white_sub = '-', char_other_sub = '-')
5
+ name.respond_to?(:gsub) ? name.gsub(%r{\s}, char_white_sub).gsub(%r{[/<>+]}, char_other_sub) : ''
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,3 @@
1
+ module Superstring
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,171 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'cgi'
4
+ require 'digest/sha1'
5
+ require 'active_support'
6
+ require 'active_support/core_ext/string'
7
+ require "superstring/version"
8
+ require "superstring/ext/gollum"
9
+
10
+ # Add functionality to basic String class:
11
+
12
+ class ::String
13
+
14
+ include ActiveSupport::Inflector
15
+
16
+ MAXIMUM_SUBDOMAIN_LENGTH = 63 # This is a hard limit set by internet standards
17
+
18
+ def sha1
19
+ Digest::SHA1.hexdigest( self )
20
+ end
21
+
22
+ def sha256
23
+ Digest::SHA256.hexdigest( self )
24
+ end
25
+
26
+ def sha384
27
+ Digest::SHA384.hexdigest( self )
28
+ end
29
+
30
+ def sha512
31
+ Digest::SHA512.hexdigest( self )
32
+ end
33
+
34
+ def sentences
35
+ self.scan(
36
+ %r{
37
+ (?:
38
+ [^.!?\s] # first char of sentence
39
+ [^\r\n]+? # body of sentence
40
+ [.!?]+ # end of sentence
41
+ (?=\s|\z) # followed by whitespace, or end of string
42
+ )
43
+ }x
44
+ )
45
+ end
46
+
47
+ def sentence_poem
48
+ sentences.join($/)
49
+ end
50
+
51
+ def slug(type = :page, minimum_subdomain_length = 8)
52
+ case type
53
+ when :page
54
+ page_name_safe
55
+ when :subdomain
56
+ padded_subdomain_safe(1)
57
+ when :padded_subdomain
58
+ padded_subdomain_safe(minimum_subdomain_length)
59
+ else
60
+ raise ArgumentError, "Unknown slug type #{type.inspect}"
61
+ end
62
+ end
63
+
64
+ def page_name_safe(char_white_sub = '-', char_other_sub = '-')
65
+ safer = self
66
+ if domain.present?
67
+ safer = CGI.unescape safer # convert %3D to '=', %20 to space, etc
68
+ safer = safer.gsub(/[?&=]/, char_other_sub) # slug out standard query string chars
69
+ end
70
+ safer = Gollum::Page.cname(safer, char_white_sub, char_other_sub)
71
+ safer
72
+ end
73
+
74
+ def padded_subdomain_safe(minimum_subdomain_length)
75
+ if minimum_subdomain_length > MAXIMUM_SUBDOMAIN_LENGTH
76
+ raise ArgumentError.new("minimum_subdomain_length must not be greater than #{MAXIMUM_SUBDOMAIN_LENGTH} (was: #{minimum_subdomain_length}")
77
+ end
78
+
79
+ massaged = subdomain_safe
80
+ if massaged.size < minimum_subdomain_length
81
+ massaged << '-' unless massaged.empty?
82
+ massaged << ( minimum_subdomain_length - massaged.size ).times.map{ (rand*10).floor.to_s }.join
83
+ end
84
+ massaged
85
+ end
86
+
87
+ def subdomain_safe
88
+ safer = page_name_safe
89
+ safer = transliterate(safer) # convert ø to o, å to a, etc
90
+ safer.downcase!
91
+ safer.gsub!(/[^a-z0-9\-]/, '-')
92
+ safer.gsub!(/^-+/, '')
93
+ safer = safer.slice(0, MAXIMUM_SUBDOMAIN_LENGTH)
94
+ safer
95
+ end
96
+
97
+ DOMAIN_SEGMENT_PATTERN = "[a-z0-9][a-z0-9-]+"
98
+ URI_PATTERN =
99
+ %r{
100
+ ^
101
+ \s* # optional leading whitespace
102
+ (?:[a-z]+:)? # optional protocol, eg http:
103
+ // # required //
104
+ (?:www\.)? # 'www.' is ignored
105
+ (
106
+ #{DOMAIN_SEGMENT_PATTERN} # first domain segment
107
+ (?:\.#{DOMAIN_SEGMENT_PATTERN})+ # one or more additional domain segments
108
+ )
109
+ (?:/|$) # followed by a '/' or end of line
110
+ }ix
111
+
112
+ def domain
113
+ match(URI_PATTERN).to_a[1]
114
+ end
115
+
116
+ def strip_lines!
117
+ line_ending = match(/\r?\n/).to_a[0] || match(/\r/).to_a[0]
118
+ lines = line_ending ? split( line_ending ) : [ self ]
119
+ lines.map!{|line| line.strip }
120
+ processed = lines.join( line_ending )
121
+ processed.strip!
122
+ replace( processed )
123
+ end
124
+
125
+ def in?( collection )
126
+ collection.nil? ? false : collection.include?( self )
127
+ end
128
+
129
+ def compact_whitespace
130
+ gsub( /\s+/, ' ' ).strip
131
+ end
132
+
133
+ #LINE_ENDING = "\n"
134
+ #
135
+ #def break_long_lines!
136
+ # lines = split( LINE_ENDING )
137
+ # lines.map!( &:break_if_long )
138
+ # processed = lines.join( LINE_ENDING )
139
+ # replace( processed )
140
+ #end
141
+ #
142
+ #def break_if_long( max_length=100 )
143
+ # lines = scan( chunk_pattern( max_length ) )
144
+ # lines.map!( &:strip )
145
+ # lines.join( LINE_ENDING )
146
+ #end
147
+ #
148
+ #def chunk_pattern( max_length )
149
+ # %r{
150
+ # (?:
151
+ # (?:\b|^)
152
+ # .{1,#{max_length}} # lines shorter than max_length
153
+ # (?:\s|$)
154
+ # |
155
+ # [^\s]{#{max_length+1},} # lines longer than max_length, but with no whitespace, so they should not be broken
156
+ # )
157
+ # }x
158
+ #end
159
+ #
160
+ #ELLIPSES = '...'
161
+ #
162
+ #def truncate( max_length )
163
+ # max_length -= ELLIPSES.size
164
+ # result = match( chunk_pattern( max_length ) ) && $1
165
+ # result ||= self[ 0...max_length ]
166
+ # result.strip!
167
+ # result << ELLIPSES if result.size < self.size
168
+ # result
169
+ #end
170
+
171
+ end
@@ -0,0 +1,140 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../lib/superstring', File.dirname(__FILE__))
4
+
5
+ describe ::String do
6
+
7
+ describe "#sha1" do
8
+ it { "x".sha1.should =~ /^[0-9a-f]{40}$/ }
9
+ end
10
+
11
+ describe "#sha384" do
12
+ it { "x".sha384.should =~ /^[0-9a-f]{96}$/ }
13
+ end
14
+
15
+ describe "#sha512" do
16
+ it { "x".sha512.should =~ /^[0-9a-f]{128}$/ }
17
+ end
18
+
19
+ describe "#sentences" do
20
+ it { "That that is, is. That that is not, is not.\n\nThat is it...is it not?".sentences.should ==
21
+ ["That that is, is.", "That that is not, is not.", "That is it...is it not?"] }
22
+ it { "Foo. Bar fight! Baz? Yo!!!".sentences.should ==
23
+ ["Foo.", "Bar fight!", "Baz?", "Yo!!!"] }
24
+ it { "This file is called _Heart of the sun.wav Nov., 2012_.".sentences.should ==
25
+ ["This file is called _Heart of the sun.wav Nov., 2012_."] }
26
+ end
27
+
28
+ describe "#sentence_poem" do
29
+ it { "That that is, is. That that is not, is not.\n\nThat is it...is it not?".sentence_poem.should ==
30
+ "That that is, is.\nThat that is not, is not.\nThat is it...is it not?" }
31
+ end
32
+
33
+ describe "#strip_lines!" do
34
+ it { " foo bar ".strip_lines!.should == "foo bar" }
35
+ it { " foo \n bar ".strip_lines!.should == "foo\nbar" }
36
+ it { " foo \r bar ".strip_lines!.should == "foo\rbar" }
37
+ it { " foo \r\n bar ".strip_lines!.should == "foo\r\nbar" }
38
+ it { "\n\nfoo\nbar\n\n".strip_lines!.should == "foo\nbar" }
39
+ end
40
+
41
+ describe "#compact_whitespace" do
42
+ it { " foo bar ".compact_whitespace.should == "foo bar" }
43
+ it { " foo \n bar ".compact_whitespace.should == "foo bar" }
44
+ it { " foo \r bar ".compact_whitespace.should == "foo bar" }
45
+ it { " foo \r\n bar ".compact_whitespace.should == "foo bar" }
46
+ it { "\n\nfoo\nbar\n\n".compact_whitespace.should == "foo bar" }
47
+ end
48
+
49
+ describe "#domain" do
50
+ it { "http://mediawiki.org".domain.should == "mediawiki.org"}
51
+ it { "http://mediawiki.org/".domain.should == "mediawiki.org"}
52
+ it { "http://mediawiki.org/foo.html".domain.should == "mediawiki.org"}
53
+ it { "https://mediawiki.org/".domain.should == "mediawiki.org"}
54
+ it { "gopher://mediawiki.org/".domain.should == "mediawiki.org"}
55
+ it { "anyprotocol://mediawiki.org/".domain.should == "mediawiki.org"}
56
+ it { "//mediawiki.org/".domain.should == "mediawiki.org"}
57
+ context "subdomains" do
58
+ it { "http://www.mediawiki.org/".domain.should == "mediawiki.org"}
59
+ it { "http://dance.dance.mediawiki.org/".domain.should == "dance.dance.mediawiki.org"}
60
+ it { "http://dance-dance-.mediawiki.org/".domain.should == "dance-dance-.mediawiki.org"}
61
+ it { "http://www.dance.dance.mediawiki.org/".domain.should == "dance.dance.mediawiki.org"}
62
+ end
63
+ context "invalid URIs" do
64
+ it { "".domain.should == nil }
65
+ it { "/mediawiki.org".domain.should == nil }
66
+ it { "http://mediawiki.org~~~".domain.should == nil }
67
+ it { "http://-illegal-subdomain.mediawiki.org".domain.should == nil }
68
+ it { "http://-illegal-subdomain.mediawiki.org".domain.should == nil }
69
+ end
70
+ end
71
+
72
+ describe "#slug" do
73
+ context "slugs safe for file names, and (arguably) URLs" do
74
+ it { "".slug(:page).should == "" }
75
+ it { "Welcome Visitors".slug(:page).should == "Welcome-Visitors" }
76
+ it { " Welcome Visitors ".slug(:page).should == "--Welcome--Visitors--" }
77
+
78
+ it { "2012 Report".slug(:page).should == "2012-Report" }
79
+ it { "Ward's Wiki".slug(:page).should == "Ward's-Wiki" }
80
+ it { "holy cats !!! you don't say".slug(:page).should == "holy-cats-!!!-you-don't-say" }
81
+
82
+ it { "ø'malley".slug(:page).should == "ø'malley" }
83
+ it { "Les Misérables".slug(:page).should == "Les-Misérables" }
84
+
85
+ context "it should URL-decode characters in clear cases" do
86
+ it { "https://www.logilab.org/view?rql=WHERE%20X%20is%20IN%28MicroBlogEntry%2C%20BlogEntry%29%2C%20X%20title%20T".slug(:page).should ==
87
+ "https:--www.logilab.org-view-rql-WHERE-X-is-IN(MicroBlogEntry,-BlogEntry),-X-title-T" }
88
+ end
89
+
90
+ context "it should not URL-decode characters when the string is not a URL" do
91
+ it { "Pride? Yes, & that = prejudice. Sometimes %20 is just %20.".slug(:page).should ==
92
+ "Pride?-Yes,-&-that-=-prejudice.-Sometimes-%20-is-just-%20." }
93
+ end
94
+
95
+ end
96
+
97
+ context "slugs safe for subdomains" do
98
+ it { "".slug(:subdomain).should =~ /^\d$/ }
99
+
100
+ it { ("1234567890"*10).slug(:subdomain).should == "1234567890"*6 + "123" } # 63 is the largest legal subdomain length
101
+
102
+ it { "Welcome Visitors".slug(:subdomain).should == "welcome-visitors" }
103
+ it { " Welcome Visitors ".slug(:subdomain).should == "welcome--visitors--" }
104
+
105
+ it { "2012 Report".slug(:subdomain).should == "2012-report" }
106
+ it { "Ward's Wiki".slug(:subdomain).should == "ward-s-wiki" }
107
+ it { "holy cats !!! you don't say".slug(:subdomain).should == "holy-cats-----you-don-t-say" }
108
+
109
+ it { "ø'målley".slug(:subdomain).should == "o-malley" }
110
+ it { "Les Misérables".slug(:subdomain).should == "les-miserables" }
111
+
112
+ it { "https://www.logilab.org/view?rql=WHERE%20X%20is%20IN%28MicroBlogEntry".slug(:subdomain).should ==
113
+ "https---www-logilab-org-view-rql-where-x-is-in-microblogentry" }
114
+
115
+ it { "Pride? Yes, & that = prejudice. Sometimes %20 is just %20.".slug(:subdomain).should ==
116
+ "pride--yes----that---prejudice--sometimes--20-is-just--20-" }
117
+ end
118
+
119
+ context "padded to meet a given minimum length" do
120
+ it { "".slug(:padded_subdomain, 0).should == '' }
121
+ it { "".slug(:padded_subdomain, 10).should =~ /^\d{10}$/ }
122
+ it { "foo".slug(:padded_subdomain, 3).should =~ /^foo$/ }
123
+ it { "foo".slug(:padded_subdomain, 4).should =~ /^foo-$/ }
124
+ it { "foo".slug(:padded_subdomain, 5).should =~ /^foo-\d$/ }
125
+ it { "foo".slug(:padded_subdomain, 63).should =~ /^foo-\d{59}$/ }
126
+ it { lambda { "foo".slug(:padded_subdomain, 64) }.should raise_error(ArgumentError) }
127
+ end
128
+
129
+ end
130
+
131
+ describe "#in?" do
132
+ it { "foo".in?(["foo", "bar"]).should == true }
133
+ it { "f00".in?(["foo", "bar"]).should == false }
134
+ it { "foo".in?([]).should == false }
135
+ it { "foo".in?(nil).should == false }
136
+ it { "".in?([]).should == false }
137
+ it { "".in?(nil).should == false }
138
+ end
139
+
140
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'superstring/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "superstring"
8
+ gem.version = Superstring::VERSION
9
+ gem.authors = ["Harlan T Wood"]
10
+ gem.email = ["code@harlantwood.net"]
11
+ gem.description = %q{Grant superpowers to instances of the String class}
12
+ gem.summary = %q{Split stings into sentences, convert to URL-friendly slugs, generate hashcodes, and more}
13
+ gem.homepage = "https://github.com/harlantwood/superstring"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'activesupport', '>= 3.0.0'
21
+ gem.add_dependency 'i18n'
22
+
23
+ gem.add_development_dependency 'rspec'
24
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: superstring
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Harlan T Wood
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: i18n
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Grant superpowers to instances of the String class
63
+ email:
64
+ - code@harlantwood.net
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .travis.yml
71
+ - Gemfile
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - lib/superstring.rb
76
+ - lib/superstring/ext/gollum.rb
77
+ - lib/superstring/version.rb
78
+ - spec/superstring_spec.rb
79
+ - superstring.gemspec
80
+ homepage: https://github.com/harlantwood/superstring
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 1.8.24
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Split stings into sentences, convert to URL-friendly slugs, generate hashcodes,
104
+ and more
105
+ test_files:
106
+ - spec/superstring_spec.rb