superstring 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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