will_scan_string 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,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in will_scan_string.gemspec
4
+ gemspec
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,3 @@
1
+ module WillScanString
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,7 @@
1
+ require "will_scan_string/version"
2
+ require "will_scan_string/string_scanner"
3
+ require "will_scan_string/regexp_traits"
4
+
5
+ module WillScanString
6
+ Regexp.send( :include, RegexpTraits )
7
+ 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 "<", "&lt;"
20
+ ss.register_replacement ">", "&gt;"
21
+ ss.register_replacement "\"", "&quot;"
22
+ ss.register_replacement "&", "&amp;"
23
+ ss.replace("& :)").should eql %{&amp; <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
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'active_support/all'
4
+
5
+ require 'will_scan_string'
6
+
7
+ RSpec.configure do |config|
8
+ # some (optional) config here
9
+ end
@@ -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