hx 0.7.4 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/hx +3 -2
- data/lib/hx.rb +48 -59
- data/lib/hx/backend/couchdb.rb +5 -3
- data/lib/hx/backend/hobix.rb +2 -3
- data/lib/hx/backend/rawfiles.rb +4 -3
- data/lib/hx/{commandline.rb → cli.rb} +2 -2
- data/lib/hx/listing/limit.rb +2 -3
- data/lib/hx/listing/paginate.rb +5 -5
- data/lib/hx/listing/recursiveindex.rb +19 -12
- data/lib/hx/output/liquidtemplate.rb +5 -9
- data/lib/hx/path.rb +208 -0
- data/lib/hx/rack/application.rb +0 -1
- data/loc.sh +3 -0
- data/spec/cache_spec.rb +4 -4
- data/spec/nullinput_spec.rb +2 -2
- data/spec/overlay_spec.rb +4 -4
- data/spec/pathops_spec.rb +6 -6
- data/spec/rack_spec.rb +2 -0
- data/spec/selector_spec.rb +150 -0
- data/spec/site_spec.rb +1 -1
- data/spec/spec_helper.rb +12 -2
- metadata +7 -5
- data/spec/pathfilter_spec.rb +0 -45
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.2
|
data/bin/hx
CHANGED
data/lib/hx.rb
CHANGED
@@ -21,12 +21,12 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'thread'
|
26
25
|
require 'set'
|
27
26
|
require 'pathname'
|
28
27
|
require 'tempfile'
|
29
28
|
require 'yaml'
|
29
|
+
require 'hx/path'
|
30
30
|
|
31
31
|
module Hx
|
32
32
|
|
@@ -38,17 +38,18 @@ end
|
|
38
38
|
class EditingNotSupportedError < RuntimeError
|
39
39
|
end
|
40
40
|
|
41
|
+
# minimal complete definition: each_entry_path + get_entry, or each_entry
|
41
42
|
module Filter
|
42
43
|
def edit_entry(path, prototype=nil)
|
43
44
|
raise EditingNotSupportedError, "Editing not supported for #{path}"
|
44
45
|
end
|
45
46
|
|
46
|
-
def each_entry_path
|
47
|
-
each_entry { |path, entry| yield path }
|
47
|
+
def each_entry_path(selector)
|
48
|
+
each_entry(selector) { |path, entry| yield path }
|
48
49
|
end
|
49
50
|
|
50
|
-
def each_entry
|
51
|
-
each_entry_path do |path|
|
51
|
+
def each_entry(selector)
|
52
|
+
each_entry_path(selector) do |path|
|
52
53
|
begin
|
53
54
|
entry = get_entry(path)
|
54
55
|
rescue NoSuchEntryError
|
@@ -59,8 +60,8 @@ module Filter
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def get_entry(path)
|
62
|
-
each_entry do |entry_path, entry|
|
63
|
-
return entry
|
63
|
+
each_entry(Path.literal(path)) do |entry_path, entry|
|
64
|
+
return entry
|
64
65
|
end
|
65
66
|
raise NoSuchEntryError, path
|
66
67
|
end
|
@@ -69,7 +70,7 @@ end
|
|
69
70
|
class NullInput
|
70
71
|
include Filter
|
71
72
|
|
72
|
-
def each_entry
|
73
|
+
def each_entry(selector)
|
73
74
|
self
|
74
75
|
end
|
75
76
|
end
|
@@ -79,13 +80,25 @@ NULL_INPUT = NullInput.new
|
|
79
80
|
class PathSubset
|
80
81
|
include Filter
|
81
82
|
|
83
|
+
def patterns_to_selector(patterns)
|
84
|
+
patterns.map { |p| Path::parse_pattern(p) }.inject { |a, b| a | b }
|
85
|
+
end
|
86
|
+
private :patterns_to_selector
|
87
|
+
|
82
88
|
def initialize(input, options)
|
83
89
|
@input = input
|
84
|
-
|
90
|
+
only = patterns_to_selector(Array(options[:only] || []))
|
91
|
+
except = patterns_to_selector(Array(options[:except] || []))
|
92
|
+
except = ~except if except
|
93
|
+
if only and except
|
94
|
+
@selector = only & except
|
95
|
+
else
|
96
|
+
@selector = only || except || Path::ALL
|
97
|
+
end
|
85
98
|
end
|
86
99
|
|
87
100
|
def edit_entry(path, prototype=nil)
|
88
|
-
if @
|
101
|
+
if @selector.accept? path
|
89
102
|
@input.edit_entry(path, prototype) { |text| yield text }
|
90
103
|
else
|
91
104
|
raise EditingNotSupportedError, "Editing not supported for #{path}"
|
@@ -93,47 +106,20 @@ class PathSubset
|
|
93
106
|
self
|
94
107
|
end
|
95
108
|
|
96
|
-
def each_entry_path
|
97
|
-
@input.each_entry_path
|
98
|
-
yield path if @path_filter.accept? path
|
99
|
-
end
|
109
|
+
def each_entry_path(selector, &block)
|
110
|
+
@input.each_entry_path(@selector & selector, &block)
|
100
111
|
self
|
101
112
|
end
|
102
113
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
class PathSubset::Predicate
|
110
|
-
def initialize(accept, reject)
|
111
|
-
@accept_re = patterns_to_re(accept)
|
112
|
-
@reject_re = patterns_to_re(reject)
|
113
|
-
end
|
114
|
-
|
115
|
-
def accept?(path)
|
116
|
-
(not @accept_re or path =~ @accept_re) and
|
117
|
-
(not @reject_re or path !~ @reject_re)
|
118
|
-
end
|
119
|
-
|
120
|
-
def patterns_to_re(patterns)
|
121
|
-
return nil if patterns.nil? or patterns.empty?
|
122
|
-
patterns = Array(patterns)
|
123
|
-
Regexp.new("(?:#{patterns.map { |p| pattern_to_re(p) }.join("|")})")
|
114
|
+
def each_entry(selector, &block)
|
115
|
+
@input.each_entry(@selector & selector, &block)
|
116
|
+
self
|
124
117
|
end
|
125
|
-
private :patterns_to_re
|
126
118
|
|
127
|
-
def
|
128
|
-
|
129
|
-
|
130
|
-
when "**"; ".*"
|
131
|
-
when "*"; "[^/]*"
|
132
|
-
else Regexp.quote(s)
|
133
|
-
end
|
134
|
-
}}$"
|
119
|
+
def get_entry(path)
|
120
|
+
raise NoSuchEntryError, path unless @selector.accept? path
|
121
|
+
@input.get_entry(path)
|
135
122
|
end
|
136
|
-
private :pattern_to_re
|
137
123
|
end
|
138
124
|
|
139
125
|
class Overlay
|
@@ -143,10 +129,10 @@ class Overlay
|
|
143
129
|
@inputs = inputs
|
144
130
|
end
|
145
131
|
|
146
|
-
def each_entry_path
|
132
|
+
def each_entry_path(selector)
|
147
133
|
seen = Set[]
|
148
134
|
@inputs.each do |input|
|
149
|
-
input.each_entry_path do |path|
|
135
|
+
input.each_entry_path(selector) do |path|
|
150
136
|
yield path unless seen.include? path
|
151
137
|
seen.add path
|
152
138
|
end
|
@@ -197,8 +183,11 @@ class AddPath
|
|
197
183
|
self
|
198
184
|
end
|
199
185
|
|
200
|
-
def each_entry_path
|
201
|
-
@input.each_entry_path
|
186
|
+
def each_entry_path(selector)
|
187
|
+
@input.each_entry_path(Path::ALL) do |path|
|
188
|
+
path = add_circumfix(path)
|
189
|
+
yield path if selector.accept? path
|
190
|
+
end
|
202
191
|
self
|
203
192
|
end
|
204
193
|
|
@@ -218,10 +207,10 @@ class StripPath
|
|
218
207
|
self
|
219
208
|
end
|
220
209
|
|
221
|
-
def each_entry_path
|
222
|
-
@input.each_entry_path do |path|
|
210
|
+
def each_entry_path(selector)
|
211
|
+
@input.each_entry_path(Path::ALL) do |path|
|
223
212
|
path = strip_circumfix(path)
|
224
|
-
yield path if path
|
213
|
+
yield path if path and selector.accept? path
|
225
214
|
end
|
226
215
|
self
|
227
216
|
end
|
@@ -246,14 +235,14 @@ class Cache
|
|
246
235
|
self
|
247
236
|
end
|
248
237
|
|
249
|
-
def each_entry
|
238
|
+
def each_entry(selector)
|
250
239
|
entries = nil
|
251
240
|
@lock.synchronize do
|
252
241
|
if @entries
|
253
242
|
entries = @entries
|
254
243
|
else
|
255
244
|
entries = []
|
256
|
-
@input.each_entry do |path, entry|
|
245
|
+
@input.each_entry(Path::ALL) do |path, entry|
|
257
246
|
@entries_by_path[path] = entry
|
258
247
|
entries << [path, entry]
|
259
248
|
end
|
@@ -261,7 +250,7 @@ class Cache
|
|
261
250
|
end
|
262
251
|
end
|
263
252
|
entries.each do |path, entry|
|
264
|
-
yield path, entry.dup
|
253
|
+
yield path, entry.dup if selector.accept? path
|
265
254
|
end
|
266
255
|
self
|
267
256
|
end
|
@@ -294,9 +283,9 @@ class Sort
|
|
294
283
|
self
|
295
284
|
end
|
296
285
|
|
297
|
-
def each_entry
|
286
|
+
def each_entry(selector)
|
298
287
|
entries = []
|
299
|
-
@input.each_entry do |path, entry|
|
288
|
+
@input.each_entry(selector) do |path, entry|
|
300
289
|
entries << [path, entry]
|
301
290
|
end
|
302
291
|
unless @key_fields.empty?
|
@@ -542,8 +531,8 @@ class Site
|
|
542
531
|
self
|
543
532
|
end
|
544
533
|
|
545
|
-
def each_entry_path
|
546
|
-
@combined_output.each_entry_path { |path| yield path }
|
534
|
+
def each_entry_path(selector)
|
535
|
+
@combined_output.each_entry_path(selector) { |path| yield path }
|
547
536
|
self
|
548
537
|
end
|
549
538
|
|
data/lib/hx/backend/couchdb.rb
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'cgi'
|
26
25
|
require 'net/http'
|
27
26
|
require 'uri'
|
@@ -81,9 +80,12 @@ class CouchDB
|
|
81
80
|
self
|
82
81
|
end
|
83
82
|
|
84
|
-
def each_entry_path
|
83
|
+
def each_entry_path(selector)
|
85
84
|
listing = JSON.parse(get_document('_all_docs'))
|
86
|
-
listing['rows'].each
|
85
|
+
listing['rows'].each do |row|
|
86
|
+
path = row['id']
|
87
|
+
yield path if selector.accept? path
|
88
|
+
end
|
87
89
|
self
|
88
90
|
end
|
89
91
|
|
data/lib/hx/backend/hobix.rb
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'yaml'
|
26
25
|
require 'hx'
|
27
26
|
require 'hx/backend/rawfiles'
|
@@ -73,8 +72,8 @@ class Hobix
|
|
73
72
|
self
|
74
73
|
end
|
75
74
|
|
76
|
-
def each_entry_path
|
77
|
-
@source.each_entry_path { |path| yield path }
|
75
|
+
def each_entry_path(selector)
|
76
|
+
@source.each_entry_path(selector) { |path| yield path }
|
78
77
|
self
|
79
78
|
end
|
80
79
|
|
data/lib/hx/backend/rawfiles.rb
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'pathname'
|
26
25
|
require 'hx'
|
27
26
|
|
@@ -56,9 +55,11 @@ class RawFiles
|
|
56
55
|
self
|
57
56
|
end
|
58
57
|
|
59
|
-
def each_entry_path
|
58
|
+
def each_entry_path(selector)
|
60
59
|
Pathname.glob(@entry_dir + '**/*') do |pathname|
|
61
|
-
|
60
|
+
next unless pathname.file?
|
61
|
+
path = pathname_to_path(pathname)
|
62
|
+
yield path if selector.accept? path
|
62
63
|
end
|
63
64
|
self
|
64
65
|
end
|
@@ -28,7 +28,7 @@ require 'pathname'
|
|
28
28
|
require 'tempfile'
|
29
29
|
|
30
30
|
module Hx
|
31
|
-
module
|
31
|
+
module CLI
|
32
32
|
|
33
33
|
DEFAULT_CONFIG_FILENAME = "config.hx"
|
34
34
|
|
@@ -105,7 +105,7 @@ end
|
|
105
105
|
|
106
106
|
def self.do_gen(site, update_only)
|
107
107
|
output_dir = Hx.get_pathname(site.options, :output_dir)
|
108
|
-
site.each_entry do |path, entry|
|
108
|
+
site.each_entry(Path::ALL) do |path, entry|
|
109
109
|
pathname = output_dir + path
|
110
110
|
content = entry['content']
|
111
111
|
if update_only
|
data/lib/hx/listing/limit.rb
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'hx'
|
26
25
|
|
27
26
|
module Hx
|
@@ -35,8 +34,8 @@ class Limit
|
|
35
34
|
@limit = options[:limit]
|
36
35
|
end
|
37
36
|
|
38
|
-
def each_entry
|
39
|
-
@input.each_entry do |path, entry|
|
37
|
+
def each_entry(selector)
|
38
|
+
@input.each_entry(selector) do |path, entry|
|
40
39
|
if entry['items']
|
41
40
|
trimmed_entry = entry.dup
|
42
41
|
trimmed_entry['items'] = entry['items'][0...@limit]
|
data/lib/hx/listing/paginate.rb
CHANGED
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'hx'
|
26
25
|
|
27
26
|
module Hx
|
@@ -35,14 +34,14 @@ class Paginate
|
|
35
34
|
@page_size = options[:page_size]
|
36
35
|
end
|
37
36
|
|
38
|
-
def each_entry
|
39
|
-
@input.each_entry do |index_path, index_entry|
|
37
|
+
def each_entry(selector)
|
38
|
+
@input.each_entry(Path::ALL) do |index_path, index_entry|
|
40
39
|
items = index_entry['items'] || []
|
41
40
|
if items.empty?
|
42
41
|
index_entry = index_entry.dup
|
43
42
|
index_entry['pages'] = [index_entry]
|
44
43
|
index_entry['page_index'] = 0
|
45
|
-
yield index_path, index_entry
|
44
|
+
yield index_path, index_entry if selector.accept? index_path
|
46
45
|
else
|
47
46
|
pages = []
|
48
47
|
n_pages = (items.size + @page_size - 1) / @page_size
|
@@ -65,7 +64,8 @@ class Paginate
|
|
65
64
|
end
|
66
65
|
pages[-1]['entry'].delete('next_page')
|
67
66
|
pages.each do |page|
|
68
|
-
|
67
|
+
path = page['path']
|
68
|
+
yield path, page['entry'] if selector.accept? path
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'hx'
|
26
25
|
require 'hx/listing/limit'
|
27
26
|
require 'hx/listing/paginate'
|
@@ -47,23 +46,31 @@ class RecursiveIndex
|
|
47
46
|
@input = input
|
48
47
|
end
|
49
48
|
|
50
|
-
def
|
49
|
+
def merge_updated(index, entry)
|
50
|
+
updated = [entry, index].map { |e| e['updated'] }.compact.max
|
51
|
+
index['updated'] = updated if updated
|
52
|
+
end
|
53
|
+
private :merge_updated
|
54
|
+
|
55
|
+
def each_entry(selector)
|
51
56
|
indexes = Hash.new { |h,k| h[k] = {'items' => []} }
|
52
|
-
@input.each_entry do |path, entry|
|
57
|
+
@input.each_entry(Path::ALL) do |path, entry|
|
53
58
|
components = path.split("/")
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
index
|
59
|
+
if components.last == "index"
|
60
|
+
index = indexes[path] = entry.merge(indexes[path])
|
61
|
+
merge_updated(index, entry)
|
62
|
+
else
|
63
|
+
until components.empty?
|
64
|
+
components.pop
|
65
|
+
index_path = (components + ["index"]).join("/")
|
66
|
+
index = indexes[index_path]
|
67
|
+
index['items'] << {'path' => path, 'entry' => entry}
|
68
|
+
merge_updated(index, entry)
|
62
69
|
end
|
63
70
|
end
|
64
71
|
end
|
65
72
|
indexes.each do |path, entry|
|
66
|
-
yield path, entry
|
73
|
+
yield path, entry if selector.accept? path
|
67
74
|
end
|
68
75
|
self
|
69
76
|
end
|
@@ -21,7 +21,6 @@
|
|
21
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
require 'rubygems'
|
25
24
|
require 'time'
|
26
25
|
require 'liquid'
|
27
26
|
require 'redcloth'
|
@@ -72,7 +71,7 @@ class LiquidTemplate
|
|
72
71
|
# same template directory for things to work right
|
73
72
|
Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_dir)
|
74
73
|
Liquid::Template.register_filter(TextFilters)
|
75
|
-
template_file = template_dir + options[:template]
|
74
|
+
template_file = template_dir + "#{options[:template]}.liquid"
|
76
75
|
@template = Liquid::Template.parse(template_file.read)
|
77
76
|
@extension = options[:extension]
|
78
77
|
@mime_type = options[:mime_type]
|
@@ -80,13 +79,10 @@ class LiquidTemplate
|
|
80
79
|
@strip_extension_re = /\.#{Regexp.quote(@extension)}$/ if @extension
|
81
80
|
end
|
82
81
|
|
83
|
-
def each_entry_path
|
84
|
-
@input.each_entry_path do |path|
|
85
|
-
unless @extension.nil?
|
86
|
-
|
87
|
-
else
|
88
|
-
yield path
|
89
|
-
end
|
82
|
+
def each_entry_path(selector)
|
83
|
+
@input.each_entry_path(Path::ALL) do |path|
|
84
|
+
path = "#{path}.#{@extension}" unless @extension.nil?
|
85
|
+
yield path if selector.accept? path
|
90
86
|
end
|
91
87
|
self
|
92
88
|
end
|
data/lib/hx/path.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
# hx/path - path selectors
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009-2010 MenTaLguY <mental@rydia.net>
|
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.
|
23
|
+
|
24
|
+
module Hx
|
25
|
+
module Path
|
26
|
+
|
27
|
+
module Selector
|
28
|
+
def prefix ; "" ; end
|
29
|
+
def suffix ; "" ; end
|
30
|
+
def regexp ; nil ; end
|
31
|
+
def remaining_suffix(prefix_consumed) ; suffix ; end
|
32
|
+
|
33
|
+
def accept?(path)
|
34
|
+
raise NotImplementedError, "#{self.class}#accept? not implemented"
|
35
|
+
end
|
36
|
+
|
37
|
+
def |(other)
|
38
|
+
Disjunction.new(self, other)
|
39
|
+
end
|
40
|
+
|
41
|
+
def &(other)
|
42
|
+
Conjunction.new(self, other)
|
43
|
+
end
|
44
|
+
|
45
|
+
def ~()
|
46
|
+
Negation.new(self)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class All
|
51
|
+
include Selector
|
52
|
+
|
53
|
+
REGEXP = Regexp.new("^.*$")
|
54
|
+
|
55
|
+
def regexp ; REGEXP ; end
|
56
|
+
def accept?(path) ; true ; end
|
57
|
+
end
|
58
|
+
|
59
|
+
ALL = All.new
|
60
|
+
|
61
|
+
class Literal
|
62
|
+
include Selector
|
63
|
+
|
64
|
+
attr_reader :value
|
65
|
+
alias prefix value
|
66
|
+
|
67
|
+
def initialize(value)
|
68
|
+
@value = value
|
69
|
+
@regexp = nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def remaining_suffix(prefix_consumed)
|
73
|
+
@value[prefix_consumed..-1]
|
74
|
+
end
|
75
|
+
|
76
|
+
def regexp
|
77
|
+
@regexp ||= Regexp.new("^#{Regexp.quote(@value)}$")
|
78
|
+
end
|
79
|
+
|
80
|
+
def accept?(path)
|
81
|
+
@value == path
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.parse_pattern(pattern_string)
|
86
|
+
tokens = []
|
87
|
+
pattern_string.scan(/(\*\*?|[^*]+)/) do |token,|
|
88
|
+
tokens << case token
|
89
|
+
when "**"; :doublestar
|
90
|
+
when "*"; :star
|
91
|
+
else; token
|
92
|
+
end
|
93
|
+
end
|
94
|
+
prefix = tokens.first
|
95
|
+
if tokens.size == 1 and String === prefix
|
96
|
+
Literal.new(prefix)
|
97
|
+
else
|
98
|
+
prefix = "" unless String === prefix
|
99
|
+
suffix = tokens.last
|
100
|
+
suffix = "" unless String === suffix
|
101
|
+
regexp = Regexp.new("^#{tokens.map { |token|
|
102
|
+
case token
|
103
|
+
when :doublestar; '.*'
|
104
|
+
when :star; '[^/]*'
|
105
|
+
else; Regexp.quote(token)
|
106
|
+
end
|
107
|
+
}}$")
|
108
|
+
Pattern.new(regexp, prefix, suffix)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.literal(literal_string)
|
113
|
+
Literal.new(literal_string)
|
114
|
+
end
|
115
|
+
|
116
|
+
class Pattern
|
117
|
+
include Selector
|
118
|
+
|
119
|
+
attr_reader :prefix
|
120
|
+
attr_reader :suffix
|
121
|
+
attr_reader :regexp
|
122
|
+
|
123
|
+
def initialize(regexp, prefix, suffix)
|
124
|
+
@regexp = regexp
|
125
|
+
@prefix = prefix
|
126
|
+
@suffix = suffix
|
127
|
+
end
|
128
|
+
|
129
|
+
def accept?(path)
|
130
|
+
!!(@regexp.match(path))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
module Connective
|
135
|
+
include Selector
|
136
|
+
|
137
|
+
attr_reader :prefix
|
138
|
+
attr_reader :suffix
|
139
|
+
|
140
|
+
def initialize(*selectors)
|
141
|
+
@selectors = selectors
|
142
|
+
prefixes = selectors.map { |s| s.prefix }
|
143
|
+
prefix_length = (prefixes.first || "").length
|
144
|
+
prefixes.each_cons(2) do |a, b|
|
145
|
+
prefix_length.downto(0) do |length|
|
146
|
+
prefix_length = length
|
147
|
+
break if a[0...length] == b[0...length]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
@prefix = prefixes.first[0...prefix_length]
|
151
|
+
suffixes = selectors.map { |s| s.remaining_suffix(prefix_length) }
|
152
|
+
suffix_length = (suffixes.first || "").length
|
153
|
+
suffixes.each_cons(2) do |a, b|
|
154
|
+
suffix_length.downto(0) do |length|
|
155
|
+
suffix_length = length
|
156
|
+
break if a[-length..-1] == b[-length..-1]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
@suffix = suffixes.first[-suffix_length..-1]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class Conjunction
|
164
|
+
include Connective
|
165
|
+
|
166
|
+
def accept?(path)
|
167
|
+
@selectors.all? { |s| s.accept? path }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class Disjunction
|
172
|
+
include Connective
|
173
|
+
|
174
|
+
attr_reader :regexp
|
175
|
+
|
176
|
+
def initialize(*selectors)
|
177
|
+
super
|
178
|
+
regexps = @selectors.map { |s| s.regexp }
|
179
|
+
if regexps.all?
|
180
|
+
@regexp = Regexp.union(*regexps)
|
181
|
+
else
|
182
|
+
@regexp = nil
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def accept?(path)
|
187
|
+
if @regexp
|
188
|
+
!!@regexp.match(path)
|
189
|
+
else
|
190
|
+
@selectors.any? { |s| s.accept? path }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class Negation
|
196
|
+
include Selector
|
197
|
+
|
198
|
+
def initialize(selector)
|
199
|
+
@selector = selector
|
200
|
+
end
|
201
|
+
|
202
|
+
def accept?(path)
|
203
|
+
not @selector.accept?(path)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
data/lib/hx/rack/application.rb
CHANGED
data/loc.sh
ADDED
data/spec/cache_spec.rb
CHANGED
@@ -12,20 +12,20 @@ describe Hx::Cache do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should return itself from each_entry" do
|
15
|
-
@cache.each_entry {}.should == @cache
|
15
|
+
@cache.each_entry(Hx::Path::ALL) {}.should == @cache
|
16
16
|
end
|
17
17
|
|
18
18
|
it "enumerates the same entries from the source" do
|
19
|
-
@cache.each_entry do |path, entry|
|
19
|
+
@cache.each_entry(Hx::Path::ALL) do |path, entry|
|
20
20
|
entry.should == @source.get_entry(path)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
it "only reads the source once" do
|
25
|
-
@cache.each_entry {}
|
25
|
+
@cache.each_entry(Hx::Path::ALL) {}
|
26
26
|
def @source.each_entry
|
27
27
|
raise RuntimeError, "should not be called"
|
28
28
|
end
|
29
|
-
@cache.each_entry {}
|
29
|
+
@cache.each_entry(Hx::Path::ALL) {}
|
30
30
|
end
|
31
31
|
end
|
data/spec/nullinput_spec.rb
CHANGED
@@ -8,11 +8,11 @@ describe Hx::NullInput do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should return itself from each_entry" do
|
11
|
-
@null_source.each_entry {}.should == @null_source
|
11
|
+
@null_source.each_entry(Hx::Path::ALL) {}.should == @null_source
|
12
12
|
end
|
13
13
|
|
14
14
|
it "enumerates no entry paths" do
|
15
|
-
@null_source.each_entry do |path, entry|
|
15
|
+
@null_source.each_entry(Hx::Path::ALL) do |path, entry|
|
16
16
|
raise RuntimeError("No entries")
|
17
17
|
end
|
18
18
|
end
|
data/spec/overlay_spec.rb
CHANGED
@@ -14,25 +14,25 @@ describe Hx::Overlay do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should return itself from each_entry" do
|
17
|
-
@overlay.each_entry {}.should == @overlay
|
17
|
+
@overlay.each_entry(Hx::Path::ALL) {}.should == @overlay
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should expose the union of paths" do
|
21
21
|
actual_paths = []
|
22
|
-
@overlay.each_entry do |path, entry|
|
22
|
+
@overlay.each_entry(Hx::Path::ALL) do |path, entry|
|
23
23
|
actual_paths << path
|
24
24
|
end
|
25
25
|
actual_paths.sort.should == %w(foo bar baz).sort
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should give earlier sources precedence" do
|
29
|
-
@overlay.each_entry do |path, entry|
|
29
|
+
@overlay.each_entry(Hx::Path::ALL) do |path, entry|
|
30
30
|
entry.should == @a.get_entry('bar') if path == 'bar'
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should expose entries from all sources" do
|
35
|
-
@overlay.each_entry do |path, entry|
|
35
|
+
@overlay.each_entry(Hx::Path::ALL) do |path, entry|
|
36
36
|
entry.should == @a.get_entry('foo') if path == 'foo'
|
37
37
|
entry.should == @b.get_entry('baz') if path == 'baz'
|
38
38
|
end
|
data/spec/pathops_spec.rb
CHANGED
@@ -14,12 +14,12 @@ describe Hx::AddPath do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should return itself from each_entry" do
|
17
|
-
@add.each_entry {}.should == @add
|
17
|
+
@add.each_entry(Hx::Path::ALL) {}.should == @add
|
18
18
|
end
|
19
19
|
|
20
20
|
it "yields augmented paths from each_entry" do
|
21
21
|
paths = Set[]
|
22
|
-
@add.each_entry do |path, entry|
|
22
|
+
@add.each_entry(Hx::Path::ALL) do |path, entry|
|
23
23
|
paths.add path
|
24
24
|
end
|
25
25
|
paths.should == @after_paths
|
@@ -36,12 +36,12 @@ describe Hx::StripPath do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should return itself from each_entry" do
|
39
|
-
@strip.each_entry {}.should == @strip
|
39
|
+
@strip.each_entry(Hx::Path::ALL) {}.should == @strip
|
40
40
|
end
|
41
41
|
|
42
42
|
it "yields stripped paths from each_entry" do
|
43
43
|
paths = Set[]
|
44
|
-
@strip.each_entry do |path, entry|
|
44
|
+
@strip.each_entry(Hx::Path::ALL) do |path, entry|
|
45
45
|
paths.add path
|
46
46
|
end
|
47
47
|
paths.should == @after_paths
|
@@ -59,12 +59,12 @@ describe Hx::PathSubset do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "returns itself from each_entry" do
|
62
|
-
@subset.each_entry {}.should == @subset
|
62
|
+
@subset.each_entry(Hx::Path::ALL) {}.should == @subset
|
63
63
|
end
|
64
64
|
|
65
65
|
it "enumerates paths according to the subset filter" do
|
66
66
|
actual_paths = Set[]
|
67
|
-
@subset.each_entry do |path, entry|
|
67
|
+
@subset.each_entry(Hx::Path::ALL) do |path, entry|
|
68
68
|
actual_paths.add path
|
69
69
|
end
|
70
70
|
actual_paths.should == Set['foo/bar', 'foo/baz']
|
data/spec/rack_spec.rb
CHANGED
@@ -3,11 +3,13 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
require 'hx'
|
4
4
|
require 'hx/rack'
|
5
5
|
require 'rack/mock'
|
6
|
+
require 'rack/lint'
|
6
7
|
|
7
8
|
describe Hx::Rack::Application do
|
8
9
|
before(:each) do
|
9
10
|
@input = FakeInput.new
|
10
11
|
@app = Hx::Rack::Application.new(@input, {})
|
12
|
+
@app = Rack::Lint.new(@app)
|
11
13
|
@service = Rack::MockRequest.new(@app)
|
12
14
|
end
|
13
15
|
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'hx/path'
|
4
|
+
|
5
|
+
describe Hx::Path::Pattern do
|
6
|
+
it "should include Hx::Path::Selector" do
|
7
|
+
Hx::Path::Pattern.should < Hx::Path::Selector
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should parse pattern strings" do
|
11
|
+
cases = [ { :pattern => "foo/**/bar",
|
12
|
+
:prefix => "foo/",
|
13
|
+
:suffix => "/bar" },
|
14
|
+
{ :pattern => "foo/*/bar",
|
15
|
+
:prefix => "foo/",
|
16
|
+
:suffix => "/bar" },
|
17
|
+
{ :pattern => "[blah",
|
18
|
+
:prefix => "[blah",
|
19
|
+
:suffix => "" },
|
20
|
+
{ :pattern => "hoge*",
|
21
|
+
:prefix => "hoge",
|
22
|
+
:suffix => "" },
|
23
|
+
{ :pattern => "*hoge",
|
24
|
+
:prefix => "",
|
25
|
+
:suffix => "hoge" } ]
|
26
|
+
for test_case in cases
|
27
|
+
pattern = Hx::Path.parse_pattern(test_case[:pattern])
|
28
|
+
pattern.prefix.should == test_case[:prefix]
|
29
|
+
pattern.suffix.should == test_case[:suffix]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should accept or reject paths" do
|
34
|
+
pattern = Hx::Path.parse_pattern("foo/bar")
|
35
|
+
pattern.should accept("foo/bar")
|
36
|
+
pattern.should_not accept("foo/baz")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should provide an equivalent regexp" do
|
40
|
+
pattern = Hx::Path.parse_pattern("foo/bar")
|
41
|
+
pattern.regexp.should_not be_nil
|
42
|
+
pattern.regexp.match("foo/bar").should_not be_nil
|
43
|
+
pattern.regexp.match("foo/bar/baz").should be_nil
|
44
|
+
|
45
|
+
pattern = Hx::Path.parse_pattern("foo/*/baz")
|
46
|
+
pattern.regexp.should_not be_nil
|
47
|
+
pattern.regexp.match("foo/baz").should be_nil
|
48
|
+
pattern.regexp.match("foo/bar/baz").should_not be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
PATHFILTER_PREFIX_CASES = [
|
53
|
+
{ :patterns => ["foo/bar", "fudge/bear"],
|
54
|
+
:prefix => "f",
|
55
|
+
:suffix => "ar" },
|
56
|
+
{ :patterns => ["foo/*/bar", "fudge/*/bear"],
|
57
|
+
:prefix => "f",
|
58
|
+
:suffix => "ar" },
|
59
|
+
{ :patterns => ["foo/bar", "fudge/*/bear"],
|
60
|
+
:prefix => "f",
|
61
|
+
:suffix => "ar" },
|
62
|
+
{ :patterns => ["bar*", "*bear"],
|
63
|
+
:prefix => "",
|
64
|
+
:suffix => "" },
|
65
|
+
{ :patterns => ["foobarbaz", "foobar*barbaz"],
|
66
|
+
:prefix => "foobar",
|
67
|
+
:suffix => "baz" },
|
68
|
+
{ :patterns => ["foobarbaz*", "foobar*barbaz"],
|
69
|
+
:prefix => "foobar",
|
70
|
+
:suffix => "" },
|
71
|
+
{ :patterns => ["*foobarbaz", "foobar*barbaz"],
|
72
|
+
:prefix => "",
|
73
|
+
:suffix => "barbaz" }
|
74
|
+
]
|
75
|
+
|
76
|
+
describe "Hx::Path::Selector disjunctions" do
|
77
|
+
it "should be possible" do
|
78
|
+
filters = ["foo/bar", "abcdefg"].map { |p| Hx::Path.parse_pattern(p) }
|
79
|
+
filter = filters.inject { |a, b| a | b }
|
80
|
+
filter.should be_a_kind_of(Hx::Path::Selector)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should accept and reject the right paths" do
|
84
|
+
filters = ["foo/bar", "abcdefg"].map { |p| Hx::Path.parse_pattern(p) }
|
85
|
+
filter = filters.inject { |a, b| a | b }
|
86
|
+
filter.should accept("foo/bar")
|
87
|
+
filter.should accept("abcdefg")
|
88
|
+
filter.should_not accept("hoge")
|
89
|
+
end
|
90
|
+
|
91
|
+
for test_case_outer in PATHFILTER_PREFIX_CASES
|
92
|
+
Proc.new do |test_case|
|
93
|
+
it "should produce optimal prefixes and suffixes" do
|
94
|
+
filters = test_case[:patterns].map { |p| Hx::Path.parse_pattern(p) }
|
95
|
+
filter = filters.inject { |a, b| a | b }
|
96
|
+
filter.prefix.should == test_case[:prefix]
|
97
|
+
filter.suffix.should == test_case[:suffix]
|
98
|
+
end
|
99
|
+
end.call(test_case_outer)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "negated Hx::Path::Selectors" do
|
104
|
+
before :each do
|
105
|
+
@pattern = ~Hx::Path.parse_pattern("foo*bar")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should be possible" do
|
109
|
+
@pattern.should be_a_kind_of(Hx::Path::Selector)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should reject what they match" do
|
113
|
+
@pattern.should_not accept("foobar")
|
114
|
+
@pattern.should accept("hoge")
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should have empty prefix and suffix" do
|
118
|
+
@pattern.prefix.should == ""
|
119
|
+
@pattern.suffix.should == ""
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "Hx::Path::Selector conjunctions" do
|
124
|
+
it "should be possible" do
|
125
|
+
filters = ["foo*", "*bar"].map { |p| Hx::Path.parse_pattern(p) }
|
126
|
+
filter = filters.inject { |a, b| a & b }
|
127
|
+
filter.should be_a_kind_of(Hx::Path::Selector)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should accept only paths matching both filters" do
|
131
|
+
filters = ["foo*", "*bar"].map { |p| Hx::Path.parse_pattern(p) }
|
132
|
+
filter = filters.inject { |a, b| a & b }
|
133
|
+
filter.should accept("foobar")
|
134
|
+
filter.should accept("fooxbar")
|
135
|
+
filter.should_not accept("lemur")
|
136
|
+
filter.should_not accept("foobear")
|
137
|
+
filter.should_not accept("rebar")
|
138
|
+
end
|
139
|
+
|
140
|
+
for test_case_outer in PATHFILTER_PREFIX_CASES
|
141
|
+
Proc.new do |test_case|
|
142
|
+
it "should produce optimal prefixes and suffixes" do
|
143
|
+
filters = test_case[:patterns].map { |p| Hx::Path.parse_pattern(p) }
|
144
|
+
filter = filters.inject { |a, b| a & b }
|
145
|
+
filter.prefix.should == test_case[:prefix]
|
146
|
+
filter.suffix.should == test_case[:suffix]
|
147
|
+
end
|
148
|
+
end.call(test_case_outer)
|
149
|
+
end
|
150
|
+
end
|
data/spec/site_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,10 @@ require 'hx'
|
|
4
4
|
require 'ostruct'
|
5
5
|
require 'spec'
|
6
6
|
require 'spec/autorun'
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
rescue LoadError
|
10
|
+
end
|
7
11
|
|
8
12
|
class FakeInput
|
9
13
|
include Hx::Filter
|
@@ -18,8 +22,8 @@ class FakeInput
|
|
18
22
|
@entries[path] = entry
|
19
23
|
end
|
20
24
|
|
21
|
-
def each_entry_path
|
22
|
-
@entries.each_key { |path| yield path }
|
25
|
+
def each_entry_path(selector)
|
26
|
+
@entries.each_key { |path| yield path if selector.accept? path }
|
23
27
|
self
|
24
28
|
end
|
25
29
|
|
@@ -32,6 +36,12 @@ class FakeInput
|
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
39
|
+
Spec::Matchers.define :accept do |value|
|
40
|
+
match do |acceptor|
|
41
|
+
acceptor.accept?(value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
35
45
|
Spec::Runner.configure do |config|
|
36
46
|
|
37
47
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MenTaLguY
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-04-25 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -48,21 +48,23 @@ files:
|
|
48
48
|
- lib/hx/backend/couchdb.rb
|
49
49
|
- lib/hx/backend/hobix.rb
|
50
50
|
- lib/hx/backend/rawfiles.rb
|
51
|
-
- lib/hx/
|
51
|
+
- lib/hx/cli.rb
|
52
52
|
- lib/hx/listing/limit.rb
|
53
53
|
- lib/hx/listing/paginate.rb
|
54
54
|
- lib/hx/listing/recursiveindex.rb
|
55
55
|
- lib/hx/output/liquidtemplate.rb
|
56
|
+
- lib/hx/path.rb
|
56
57
|
- lib/hx/rack.rb
|
57
58
|
- lib/hx/rack/application.rb
|
59
|
+
- loc.sh
|
58
60
|
- spec/cache_spec.rb
|
59
61
|
- spec/hx_dummy.rb
|
60
62
|
- spec/hx_dummy2.rb
|
61
63
|
- spec/nullinput_spec.rb
|
62
64
|
- spec/overlay_spec.rb
|
63
|
-
- spec/pathfilter_spec.rb
|
64
65
|
- spec/pathops_spec.rb
|
65
66
|
- spec/rack_spec.rb
|
67
|
+
- spec/selector_spec.rb
|
66
68
|
- spec/site_spec.rb
|
67
69
|
- spec/spec.opts
|
68
70
|
- spec/spec_helper.rb
|
@@ -98,10 +100,10 @@ test_files:
|
|
98
100
|
- spec/spec_helper.rb
|
99
101
|
- spec/cache_spec.rb
|
100
102
|
- spec/hx_dummy.rb
|
101
|
-
- spec/pathfilter_spec.rb
|
102
103
|
- spec/nullinput_spec.rb
|
103
104
|
- spec/site_spec.rb
|
104
105
|
- spec/hx_dummy2.rb
|
105
106
|
- spec/rack_spec.rb
|
106
107
|
- spec/overlay_spec.rb
|
107
108
|
- spec/pathops_spec.rb
|
109
|
+
- spec/selector_spec.rb
|
data/spec/pathfilter_spec.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
require 'hx'
|
4
|
-
|
5
|
-
describe Hx::PathSubset::Predicate do
|
6
|
-
it "accepts anything when the accept and reject patterns are nil" do
|
7
|
-
filter = Hx::PathSubset::Predicate.new(nil, nil)
|
8
|
-
filter.accept?("blah").should be_true
|
9
|
-
end
|
10
|
-
|
11
|
-
it "accepts only paths matching the accept pattern when it is specified" do
|
12
|
-
filter = Hx::PathSubset::Predicate.new("foo", nil)
|
13
|
-
filter.accept?("foo").should be_true
|
14
|
-
filter.accept?("bar").should be_false
|
15
|
-
end
|
16
|
-
|
17
|
-
it "accepts only paths not matching reject, when only that is specified" do
|
18
|
-
filter = Hx::PathSubset::Predicate.new(nil, "foo")
|
19
|
-
filter.accept?("foo").should be_false
|
20
|
-
filter.accept?("bar").should be_true
|
21
|
-
end
|
22
|
-
|
23
|
-
it "matches the difference of accept and reject when both are specified" do
|
24
|
-
filter = Hx::PathSubset::Predicate.new("foo/*", "foo/bar")
|
25
|
-
filter.accept?("foo/bar").should be_false
|
26
|
-
filter.accept?("foo/baz").should be_true
|
27
|
-
filter.accept?("bar").should be_false
|
28
|
-
end
|
29
|
-
|
30
|
-
it "shouldn't match across slashes with single star" do
|
31
|
-
filter = Hx::PathSubset::Predicate.new("foo/*", nil)
|
32
|
-
filter.accept?("bar").should be_false
|
33
|
-
filter.accept?("foo").should be_false
|
34
|
-
filter.accept?("foo/bar").should be_true
|
35
|
-
filter.accept?("foo/bar/baz").should be_false
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should match across slashes with double star" do
|
39
|
-
filter = Hx::PathSubset::Predicate.new("foo/**", nil)
|
40
|
-
filter.accept?("bar").should be_false
|
41
|
-
filter.accept?("foo").should be_false
|
42
|
-
filter.accept?("foo/bar").should be_true
|
43
|
-
filter.accept?("foo/bar/baz").should be_true
|
44
|
-
end
|
45
|
-
end
|