filtri 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 +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
|