filtri 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +15 -0
- data/README.md +63 -0
- data/Rakefile +5 -0
- data/filtri.gemspec +31 -0
- data/lib/filtri.rb +183 -0
- data/lib/filtri/version.rb +6 -0
- data/spec/filtri_spec.rb +223 -0
- metadata +159 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Copyright (c) 2013 Karl L <karl@ninjacontrol.com>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
|
8
|
+
the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
11
|
+
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
13
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
14
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
15
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
Filtri
|
2
|
+
======
|
3
|
+
|
4
|
+
Filtri is a tiny DSL for text substitution.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
$ gem install filtri
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
Define a set of substitution rules using `rule` and apply to an input string:
|
13
|
+
|
14
|
+
in_str = "foobazbarfoo"
|
15
|
+
expected = "barbugbarbar"
|
16
|
+
|
17
|
+
f = filtri do
|
18
|
+
rule /fo+/ => "bar"
|
19
|
+
rule "baz" => "bug"
|
20
|
+
end
|
21
|
+
|
22
|
+
f.apply("foobazbarfoo")
|
23
|
+
=> "barbugbarbar"
|
24
|
+
|
25
|
+
Rules can also be read from a file:
|
26
|
+
|
27
|
+
File `foo.rules`:
|
28
|
+
|
29
|
+
# this is a comment
|
30
|
+
rule /fo+bar/ => "bazbag"
|
31
|
+
rule /(a)+/ => '!!\1!!'
|
32
|
+
rule /(b)+/ => '**\1**'
|
33
|
+
|
34
|
+
Load with `Filtri::load`:
|
35
|
+
|
36
|
+
Filtri.load("foo.rules").apply("foobarfoobar")
|
37
|
+
=> "**b**!!a!!z**b**!!a!!g**b**!!a!!z**b**!!a!!g"
|
38
|
+
|
39
|
+
## Version information
|
40
|
+
|
41
|
+
* 0.0.1 - Initial version
|
42
|
+
|
43
|
+
## License
|
44
|
+
|
45
|
+
Copyright (c) 2013 Karl L <karl@ninjacontrol.com>
|
46
|
+
|
47
|
+
MIT License
|
48
|
+
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
|
50
|
+
"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
|
52
|
+
the following conditions:
|
53
|
+
|
54
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
55
|
+
|
56
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
57
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
58
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
59
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
60
|
+
|
61
|
+
## Author
|
62
|
+
|
63
|
+
Karl L, <karl@ninjacontrol.com>
|
data/Rakefile
ADDED
data/filtri.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'filtri/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
|
8
|
+
spec.name = "filtri"
|
9
|
+
spec.version = Filtri::VERSION
|
10
|
+
spec.authors = ["karl l"]
|
11
|
+
spec.email = ["karl@ninjacontrol.com"]
|
12
|
+
spec.date = '2013-04-01'
|
13
|
+
spec.summary = "A tiny DSL for filtering strings"
|
14
|
+
spec.description = "Filtri is a little DSL that simplifies the work of applying multiple substitution rules to a string."
|
15
|
+
spec.homepage = "https://github.com/karlll/filtri/"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_runtime_dependency "docile"
|
27
|
+
spec.add_runtime_dependency "str2hash"
|
28
|
+
spec.add_runtime_dependency "to_regexp"
|
29
|
+
|
30
|
+
end
|
31
|
+
|
data/lib/filtri.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'docile'
|
2
|
+
require 'pp'
|
3
|
+
require 'to_regexp'
|
4
|
+
require 'str2hash'
|
5
|
+
|
6
|
+
# Filtri DSL
|
7
|
+
# @author karl l <karl@ninjacontrol.com>
|
8
|
+
class Filtri
|
9
|
+
|
10
|
+
# The rules
|
11
|
+
attr_reader :rules
|
12
|
+
# The meta rules
|
13
|
+
attr_reader :meta_rules
|
14
|
+
|
15
|
+
# @private
|
16
|
+
RULES = [:rule, :meta]
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@rules = []
|
22
|
+
@meta_rules = []
|
23
|
+
@passes = 1
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add a filtering rule
|
27
|
+
# @param [Hash{Regexp => String},Hash{String => String}] rule_hash
|
28
|
+
def rule(rule_hash)
|
29
|
+
add_rule(@rules, rule_hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Add a meta rule
|
33
|
+
# @param [Hash{Regexp=>String}] rule_hash
|
34
|
+
def meta(rule_hash)
|
35
|
+
add_rule(@meta_rules, rule_hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a rule to the current rule-set
|
39
|
+
# @param [Array<Hash{Regexp => String},Hash{String => String}>] rule_set
|
40
|
+
# @param [Hash{Regexp => String},Hash{String => String}] rule_hash
|
41
|
+
# @private
|
42
|
+
def add_rule(rule_set, rule_hash)
|
43
|
+
|
44
|
+
rule_hash.each_key do |k|
|
45
|
+
rule_set << { from: k, to: rule_hash[k] }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param [Regexp, String] val
|
51
|
+
# @param [Hash{Regexp => String},Hash{String => String}] rule
|
52
|
+
# @private
|
53
|
+
def do_rewrite(val, rule)
|
54
|
+
case val
|
55
|
+
when Regexp
|
56
|
+
val_str = PP.singleline_pp(val, "")
|
57
|
+
val_str.gsub!(rule[:from], rule[:to])
|
58
|
+
val_str.to_regexp
|
59
|
+
when String
|
60
|
+
val.gsub(rule[:from], rule[:to])
|
61
|
+
else
|
62
|
+
val
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# Rewrite a hash with a set of rules
|
68
|
+
# @param [Hash{Regexp => String},Hash{String => String}] in_hash
|
69
|
+
# @param [Hash{Regexp => String},Hash{String => String}] rules
|
70
|
+
# @private
|
71
|
+
def rewrite(in_hash, rules)
|
72
|
+
out_hash = []
|
73
|
+
in_hash.each do |v|
|
74
|
+
f = v[:from]
|
75
|
+
t = v[:to]
|
76
|
+
|
77
|
+
rules.each do |r|
|
78
|
+
f = do_rewrite(f, r)
|
79
|
+
t = do_rewrite(t, r)
|
80
|
+
end
|
81
|
+
out_hash << { from: f, to: t }
|
82
|
+
end
|
83
|
+
out_hash
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Apply filtering rules to the provided string
|
88
|
+
# @param [String] in_str
|
89
|
+
# @return [String] the resulting string
|
90
|
+
def apply(in_str)
|
91
|
+
|
92
|
+
@passes.times do
|
93
|
+
|
94
|
+
unless @meta_rules.empty?
|
95
|
+
@rules = rewrite(@rules, @meta_rules)
|
96
|
+
end
|
97
|
+
|
98
|
+
@rules.each do |rule|
|
99
|
+
in_str = in_str.gsub(rule[:from], rule[:to])
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
in_str
|
104
|
+
end
|
105
|
+
|
106
|
+
# Factory, init with rule-set from a string
|
107
|
+
#
|
108
|
+
# The input string is expected to contain rules and comments, one per line,
|
109
|
+
# separated by a line break.
|
110
|
+
# The expected format of a line is "{operation} <space> {argument} <eol>".
|
111
|
+
# Empty lines and lines starting with a '#' are ignored. Whitespace at the beginning of a line
|
112
|
+
# is trimmed.
|
113
|
+
#
|
114
|
+
# @param [String] rule_str
|
115
|
+
# @return [Filtri] A new Filtri object with the rules parsed from the provided string(s).
|
116
|
+
# @raise [FiltriInitError] if an error occurs when initialising the rules from the provided strings
|
117
|
+
def self.from_str(rule_str)
|
118
|
+
|
119
|
+
inst = Filtri.new
|
120
|
+
|
121
|
+
rule_str.strip.lines do |l|
|
122
|
+
|
123
|
+
op_str = l.strip.partition " "
|
124
|
+
if op_str[0].length > 0
|
125
|
+
op = op_str[0]
|
126
|
+
op_arg = op_str[2]
|
127
|
+
|
128
|
+
if Filtri::RULES.include? op.to_sym
|
129
|
+
# parse arg string
|
130
|
+
begin
|
131
|
+
arg_hash = op_arg.to_h
|
132
|
+
rescue Parslet::ParseFailed => err
|
133
|
+
raise FiltriInitError, "Invalid rule format: '#{op_arg}' (#{err.message})"
|
134
|
+
end
|
135
|
+
# add rule
|
136
|
+
inst.send(op.to_sym,arg_hash)
|
137
|
+
else
|
138
|
+
raise FiltriInitError, "Unknown rule: #{op}" unless op == "#"
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
inst
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
# Load rules from a file
|
149
|
+
# @param [String] file_name
|
150
|
+
# @return [Filtri] A new Filtri object with the rules contained in the file
|
151
|
+
# @raise [IOError,SystemCallError] If an error occurs when opening the file
|
152
|
+
# @raise [FiltriInitError] If an error occurs when parsing the rules in the file
|
153
|
+
def self.load(file_name)
|
154
|
+
|
155
|
+
data = IO.read(file_name)
|
156
|
+
Filtri.from_str(data)
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
class FiltriInitError < StandardError
|
164
|
+
def initialize(msg)
|
165
|
+
super(msg)
|
166
|
+
@msg = msg
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# Create a Filtri object containing a set of rules
|
172
|
+
#
|
173
|
+
# @example
|
174
|
+
#
|
175
|
+
# f = filtri do
|
176
|
+
# rule "foo" => "bar"
|
177
|
+
# rule "baz" => "bug"
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# @return [Filtri] A new Filtri object containing the provided rules
|
181
|
+
def filtri(&block)
|
182
|
+
Docile.dsl_eval(Filtri.new, &block)
|
183
|
+
end
|
data/spec/filtri_spec.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "filtri"
|
3
|
+
|
4
|
+
describe Filtri do
|
5
|
+
|
6
|
+
it "applies a rule to translate a string" do
|
7
|
+
|
8
|
+
in_str = "foo\nbaz\nbar\nfoo"
|
9
|
+
expected = "bar\nbug\nbar\nbar"
|
10
|
+
|
11
|
+
f = filtri do
|
12
|
+
rule "foo" => "bar"
|
13
|
+
rule "baz" => "bug"
|
14
|
+
end
|
15
|
+
|
16
|
+
result = f.apply(in_str)
|
17
|
+
expect(result).to eq(expected)
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
it "applies a simple regexp rule to translate a string" do
|
23
|
+
|
24
|
+
in_str = "foo\nbaz\nbar\nfoo"
|
25
|
+
expected = "bar\nbug\nbar\nbar"
|
26
|
+
|
27
|
+
f = filtri do
|
28
|
+
rule /fo+/ => "bar"
|
29
|
+
rule "baz" => "bug"
|
30
|
+
end
|
31
|
+
|
32
|
+
result = f.apply(in_str)
|
33
|
+
expect(result).to eq(expected)
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
it "applies a regexp and include matches in the result" do
|
39
|
+
|
40
|
+
in_str = "This is a test XXXXX"
|
41
|
+
expected = "This is a passing test ! (XXXXX)"
|
42
|
+
|
43
|
+
f = filtri do
|
44
|
+
rule /(test)/ => 'passing \1'
|
45
|
+
rule /(X+)/ => '! (\1)'
|
46
|
+
end
|
47
|
+
|
48
|
+
result = f.apply(in_str)
|
49
|
+
expect(result).to eq(expected)
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
it "re-writes rules with meta-rules" do
|
56
|
+
|
57
|
+
in_str = "foo\nbaz\nbar\nfoo"
|
58
|
+
expected = "bar\nbug\nbar\nbar"
|
59
|
+
|
60
|
+
|
61
|
+
f = filtri do
|
62
|
+
meta /META/ => 'fo+'
|
63
|
+
rule /META/ => "bar"
|
64
|
+
rule "baz" => "bug"
|
65
|
+
end
|
66
|
+
|
67
|
+
result = f.apply(in_str)
|
68
|
+
expect(result).to eq(expected)
|
69
|
+
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
it "re-writes regexps and plain strings with meta-rules" do
|
74
|
+
|
75
|
+
in_str = "foobarfoobar"
|
76
|
+
expected = "bazbagbazbag"
|
77
|
+
|
78
|
+
|
79
|
+
f = filtri do
|
80
|
+
meta "FB" => "foobar"
|
81
|
+
rule /FB/ => "bazbag"
|
82
|
+
end
|
83
|
+
|
84
|
+
result = f.apply(in_str)
|
85
|
+
expect(result).to eq(expected)
|
86
|
+
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
it "applies meta-rules on both parts of the rule" do
|
91
|
+
|
92
|
+
in_str = "foobarfoobar"
|
93
|
+
expected = "bazbagbazbag"
|
94
|
+
|
95
|
+
|
96
|
+
f = filtri do
|
97
|
+
meta "FB" => "bazbag"
|
98
|
+
rule /foobar/ => "FB"
|
99
|
+
end
|
100
|
+
|
101
|
+
result = f.apply(in_str)
|
102
|
+
expect(result).to eq(expected)
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
it "parses rules from strings" do
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
in_str = "foobarfoobar"
|
112
|
+
expected = "bazbagbazbag"
|
113
|
+
|
114
|
+
strings = <<EOF
|
115
|
+
|
116
|
+
rule /fo+bar/ => "bazbag"
|
117
|
+
|
118
|
+
EOF
|
119
|
+
|
120
|
+
|
121
|
+
result = Filtri.from_str(strings).apply(in_str)
|
122
|
+
|
123
|
+
expect(result).to eq(expected)
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
it "parses rules with comments and empty lines" do
|
128
|
+
|
129
|
+
in_str = "foobarfoobar"
|
130
|
+
expected = "**b**!!a!!z**b**!!a!!g**b**!!a!!z**b**!!a!!g"
|
131
|
+
|
132
|
+
strings = %q(
|
133
|
+
|
134
|
+
# this is a comment
|
135
|
+
rule /fo+bar/ => "bazbag"
|
136
|
+
rule /(a)+/ => '!!\1!!'
|
137
|
+
rule /(b)+/ => '**\1**'
|
138
|
+
|
139
|
+
# empty line above
|
140
|
+
rule "text" => "some other text"
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
)
|
145
|
+
|
146
|
+
|
147
|
+
f = Filtri.from_str(strings)
|
148
|
+
result = f.apply(in_str)
|
149
|
+
|
150
|
+
expect(result).to eq(expected)
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
it "raises an exception when parsing an unknown rule" do
|
155
|
+
|
156
|
+
|
157
|
+
strings = %q(
|
158
|
+
|
159
|
+
# Below are valid rules
|
160
|
+
|
161
|
+
meta /XXX/ => "YYYYY"
|
162
|
+
rule /FOO/ => "BAR"
|
163
|
+
|
164
|
+
# Below is an unknown rule name
|
165
|
+
stupid_rule /BAG/ => "BAR"
|
166
|
+
|
167
|
+
)
|
168
|
+
expect { Filtri.from_str(strings) }.to raise_error(FiltriInitError)
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
it "raises an exception when parsing an invalid rule format" do
|
173
|
+
|
174
|
+
|
175
|
+
strings = %q(
|
176
|
+
|
177
|
+
# Below are valid rules
|
178
|
+
|
179
|
+
meta /XXX/ => "YYYYY"
|
180
|
+
rule /FOO/ => "BAR"
|
181
|
+
|
182
|
+
# Below is an a rule w. invalid format
|
183
|
+
rule NOT_VALID
|
184
|
+
|
185
|
+
)
|
186
|
+
expect { Filtri.from_str(strings) }.to raise_error(FiltriInitError)
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
it "loads rules from external files" do
|
192
|
+
|
193
|
+
in_str = "foobarfoobar"
|
194
|
+
expected = "bazbagbazbag"
|
195
|
+
|
196
|
+
|
197
|
+
content = %q(
|
198
|
+
|
199
|
+
# this is a comment
|
200
|
+
rule /fo+bar/ => "bazbag"
|
201
|
+
|
202
|
+
)
|
203
|
+
|
204
|
+
IO.stub(:read).with("test.filtri").and_return content
|
205
|
+
|
206
|
+
filename = "test.filtri"
|
207
|
+
|
208
|
+
result = Filtri.load(filename).apply(in_str)
|
209
|
+
|
210
|
+
expect(result).to eq(expected)
|
211
|
+
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
it "raises an exception when file is missing" do
|
216
|
+
|
217
|
+
|
218
|
+
expect { Filtri.load("stupid_invalid_file") }.to raise_error(SystemCallError)
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: filtri
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- karl l
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
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
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: docile
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: str2hash
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: to_regexp
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Filtri is a little DSL that simplifies the work of applying multiple
|
111
|
+
substitution rules to a string.
|
112
|
+
email:
|
113
|
+
- karl@ninjacontrol.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- filtri.gemspec
|
124
|
+
- lib/filtri.rb
|
125
|
+
- lib/filtri/version.rb
|
126
|
+
- spec/filtri_spec.rb
|
127
|
+
homepage: https://github.com/karlll/filtri/
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ! '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
segments:
|
141
|
+
- 0
|
142
|
+
hash: 1607576313604211744
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
none: false
|
145
|
+
requirements:
|
146
|
+
- - ! '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
segments:
|
150
|
+
- 0
|
151
|
+
hash: 1607576313604211744
|
152
|
+
requirements: []
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 1.8.24
|
155
|
+
signing_key:
|
156
|
+
specification_version: 3
|
157
|
+
summary: A tiny DSL for filtering strings
|
158
|
+
test_files:
|
159
|
+
- spec/filtri_spec.rb
|