will_scan_string 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 +4 -0
- data/Gemfile +4 -0
- data/README.md +20 -0
- data/Rakefile +1 -0
- data/lib/will_scan_string/regexp_traits.rb +12 -0
- data/lib/will_scan_string/string_scanner.rb +51 -0
- data/lib/will_scan_string/version.rb +3 -0
- data/lib/will_scan_string.rb +7 -0
- data/spec/lib/will_scan_string/regexp_traits_spec.rb +41 -0
- data/spec/lib/will_scan_string/string_scanner_spec.rb +32 -0
- data/spec/spec_helper.rb +9 -0
- data/will_scan_string.gemspec +24 -0
- metadata +95 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Will scan string
|
2
|
+
================
|
3
|
+
Multi-pass string replacement has always been fun. I don't know any good way to
|
4
|
+
perform multiple replacements on strings, so I made this minor gem.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
-----
|
8
|
+
Just don't use this, but if you're curious: Check `spec/lib/will_scan_string`
|
9
|
+
for examples and features.
|
10
|
+
|
11
|
+
Notes
|
12
|
+
-----
|
13
|
+
This gem is buggy and nowhere friendly to use. It's designed for personal use
|
14
|
+
and is very experimental. It uses various hacks to combine multiple regular
|
15
|
+
expressions to a single big-ass regular expression and it therefore is quite
|
16
|
+
common for 2 regular expressions conflicting each other.
|
17
|
+
|
18
|
+
Known regexp conflicts and issues
|
19
|
+
---------------------------------
|
20
|
+
- The gem does not support named capture groups whatsoever.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module WillScanString
|
2
|
+
module RegexpTraits
|
3
|
+
CAPTURE_GROUP_PATTERN = /(?<!\\)\((?:\?(?:<([a-z]+)\>|'([a-z]+)')|(?!\?))/i
|
4
|
+
|
5
|
+
def capture_groups
|
6
|
+
c = 0
|
7
|
+
r = []
|
8
|
+
source.scan(CAPTURE_GROUP_PATTERN) { r.push $+.present? ? $+.to_sym : c+=1 }
|
9
|
+
r
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module WillScanString
|
2
|
+
class StringScanner
|
3
|
+
def register_replacement( pattern, replacement )
|
4
|
+
@replacements = [] if @replacements.nil?
|
5
|
+
@replacements << [ pattern, replacement, @replacements.last.present? ? @replacements.last[2] + (@replacements.last[0].is_a?(Regexp) ? @replacements.last[0].capture_groups.length : 0) + 1 : 0 ]
|
6
|
+
@replacements_regexp = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def replace( string )
|
10
|
+
string.gsub(replacement_regexp) do
|
11
|
+
m, r = *get_match_and_replacement( $~ )
|
12
|
+
execute_replacement_with_match r, m
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def get_match_and_replacement( m )
|
18
|
+
m = m.to_a.tap{ |m| m.shift }
|
19
|
+
i = m.find_index{ |v| v.present? }
|
20
|
+
r = find_replacement_by_index(i)
|
21
|
+
cps = [0] + (r[0].is_a?(Regexp) ? r[0].capture_groups : [])
|
22
|
+
m = m[i, cps.length]
|
23
|
+
[m, r[1]]
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute_replacement_with_match( r, m )
|
27
|
+
r.is_a?(Proc) ? r.call(*m) : r.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_replacement_by_index( i )
|
31
|
+
@replacements.find{ |r| r[2] == i }
|
32
|
+
end
|
33
|
+
|
34
|
+
def replacement_regexp
|
35
|
+
@replacements_regexp ||= reconstruct_replacement_regexp
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def reconstruct_replacement_regexp
|
40
|
+
additional_offset = 1
|
41
|
+
pattern = @replacements.map(&:first).map{ |pat|
|
42
|
+
cpsc = pat.is_a?(Regexp) ? pat.capture_groups.length : 0
|
43
|
+
pat = pat.is_a?(Regexp) ? pat.source : Regexp.escape(pat.to_s)
|
44
|
+
pat.gsub!(/(?<!\\\\)(?<=\\)(\d+)/){ $1.to_i + additional_offset }
|
45
|
+
additional_offset += 1 + cpsc
|
46
|
+
"(#{pat})"
|
47
|
+
}.join "|"
|
48
|
+
/(?:#{pattern})/
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe WillScanString::RegexpTraits do
|
4
|
+
it "should match regular capture groups" do
|
5
|
+
/(a)/.capture_groups.should eql [ 1 ]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should not match escaped capture groups" do
|
9
|
+
/\(\)/.capture_groups.should eql []
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should match named capture groups with less-than & greater-than characters" do
|
13
|
+
/(?<a>a)/.capture_groups.should eql [ :a ]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should match named capture groups with single quotes" do
|
17
|
+
/(?'a'a)/.capture_groups.should eql [ :a ]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should match nested regular capture groups" do
|
21
|
+
/(a(b))/.capture_groups.should eql [ 1, 2 ]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should ignore non-capture groups" do
|
25
|
+
/(?:a)/.capture_groups.should eql []
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should ignore look-aheads and look-behinds" do
|
29
|
+
/(?=)/.capture_groups.should eql []
|
30
|
+
/(?!)/.capture_groups.should eql []
|
31
|
+
/(?<=)/.capture_groups.should eql []
|
32
|
+
/(?<!)/.capture_groups.should eql []
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should match the capture groups in my bbcode gem's regular expressions" do
|
36
|
+
/\[(\/?)([a-z0-9_-]*)(\s*=?(?:(?:\s*(?:(?:[a-z0-9_-]+)|(?<=\=))\s*[:=]\s*)?(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*'|[^\]\s,]+|(?<=,)(?=\s*,))\s*,?\s*)*)\]/i.capture_groups.should \
|
37
|
+
eql [ 1, 2, 3 ]
|
38
|
+
/(?:\s*(?:([a-z0-9_-]+)|^)\s*[:=]\s*)?("[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*'|[^\]\s,]+|(?<=,)(?=\s*,))\s*,?/i.capture_groups.should \
|
39
|
+
eql [ 1, 2 ]
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe WillScanString::StringScanner do
|
4
|
+
it "should perform a regular replacement" do
|
5
|
+
ss = WillScanString::StringScanner.new
|
6
|
+
ss.register_replacement ":)", "HAPPY"
|
7
|
+
ss.replace(":)").should eql "HAPPY"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should perform a regexp replacement with a capture group" do
|
11
|
+
ss = WillScanString::StringScanner.new
|
12
|
+
ss.register_replacement %r{<([a-z]+)>.*?</\1>}, ->(_, tagname){ "#{tagname}" }
|
13
|
+
ss.replace("<strong>hi!</strong>").should eql("strong")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not replace replaced strings" do
|
17
|
+
ss = WillScanString::StringScanner.new
|
18
|
+
ss.register_replacement ":)", %{<img src="happy.png" alt=":)" title=":)">}
|
19
|
+
ss.register_replacement "<", "<"
|
20
|
+
ss.register_replacement ">", ">"
|
21
|
+
ss.register_replacement "\"", """
|
22
|
+
ss.register_replacement "&", "&"
|
23
|
+
ss.replace("& :)").should eql %{& <img src="happy.png" alt=":)" title=":)">}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to use multiple regular expressions to replace with" do
|
27
|
+
ss = WillScanString::StringScanner.new
|
28
|
+
ss.register_replacement /(a)(b)/, "AB"
|
29
|
+
ss.register_replacement /(c)(d)/, "CD"
|
30
|
+
ss.replace("abcd").should eql "ABCD"
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "will_scan_string/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "will_scan_string"
|
7
|
+
s.version = WillScanString::VERSION
|
8
|
+
s.authors = ["Toby Hinloopen"]
|
9
|
+
s.email = ["toby@kutcomputers.nl"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Gem for string replacements using multiple regular expressions in a single pass.}
|
12
|
+
s.description = %q{Gem for string replacements using multiple regular expressions in a single pass.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "will_scan_string"
|
15
|
+
|
16
|
+
s.add_development_dependency "rspec", "~> 2.6"
|
17
|
+
s.add_dependency "activesupport", "~> 3.0.9"
|
18
|
+
s.add_dependency "i18n", "~> 0.5.0"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: will_scan_string
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Toby Hinloopen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-04 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70303473805000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.6'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70303473805000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70303473803740 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.9
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70303473803740
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: i18n
|
38
|
+
requirement: &70303473802140 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.5.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70303473802140
|
47
|
+
description: Gem for string replacements using multiple regular expressions in a single
|
48
|
+
pass.
|
49
|
+
email:
|
50
|
+
- toby@kutcomputers.nl
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- README.md
|
58
|
+
- Rakefile
|
59
|
+
- lib/will_scan_string.rb
|
60
|
+
- lib/will_scan_string/regexp_traits.rb
|
61
|
+
- lib/will_scan_string/string_scanner.rb
|
62
|
+
- lib/will_scan_string/version.rb
|
63
|
+
- spec/lib/will_scan_string/regexp_traits_spec.rb
|
64
|
+
- spec/lib/will_scan_string/string_scanner_spec.rb
|
65
|
+
- spec/spec_helper.rb
|
66
|
+
- will_scan_string.gemspec
|
67
|
+
homepage: ''
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project: will_scan_string
|
87
|
+
rubygems_version: 1.8.11
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Gem for string replacements using multiple regular expressions in a single
|
91
|
+
pass.
|
92
|
+
test_files:
|
93
|
+
- spec/lib/will_scan_string/regexp_traits_spec.rb
|
94
|
+
- spec/lib/will_scan_string/string_scanner_spec.rb
|
95
|
+
- spec/spec_helper.rb
|