hx 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/hx/cli.rb +26 -9
- data/lib/hx/output/liquidtemplate.rb +2 -2
- data/lib/hx/path.rb +24 -100
- data/lib/hx/rack/application.rb +4 -4
- data/spec/rack_spec.rb +5 -5
- data/spec/selector_spec.rb +18 -83
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.3
|
data/lib/hx/cli.rb
CHANGED
@@ -42,6 +42,7 @@ Usage: hx [--config CONFIG_FILE] [upgen]
|
|
42
42
|
hx [--config CONFIG_FILE] regen
|
43
43
|
hx [--config CONFIG_FILE] post[up] SOURCE:PATH
|
44
44
|
hx [--config CONFIG_FILE] edit[up] SOURCE:PATH
|
45
|
+
hx [--config CONFIG_FILE] list SOURCE:PATTERN
|
45
46
|
|
46
47
|
EOS
|
47
48
|
|
@@ -128,31 +129,47 @@ def self.cmd_postup(site, entry_spec)
|
|
128
129
|
cmd_upgen(site)
|
129
130
|
end
|
130
131
|
|
131
|
-
def self.
|
132
|
+
def self._parse_entry_spec(site, entry_spec)
|
132
133
|
source_name, path = entry_spec.split(':', 2)
|
134
|
+
source = site.sources[source_name]
|
135
|
+
raise ArgumentError, "No such source #{source_name}" unless source
|
136
|
+
return source, path
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.parse_entry_spec(site, entry_spec)
|
140
|
+
source, path = _parse_entry_spec(site, entry_spec)
|
133
141
|
raise "Invalid entry specification #{entry_spec}" unless path
|
134
|
-
return
|
142
|
+
return source, path
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.parse_entry_pattern(site, entry_pattern)
|
146
|
+
source, pattern = _parse_entry_spec(site, entry_pattern)
|
147
|
+
pattern = "**" unless pattern
|
148
|
+
selector = Hx::Path.parse_pattern(pattern)
|
149
|
+
return source, selector
|
135
150
|
end
|
136
151
|
|
137
152
|
def self.cmd_edit(site, entry_spec)
|
138
|
-
|
139
|
-
do_edit(site,
|
153
|
+
source, path = parse_entry_spec(site, entry_spec)
|
154
|
+
do_edit(site, source, path, nil)
|
140
155
|
end
|
141
156
|
|
142
157
|
def self.cmd_post(site, entry_spec)
|
143
|
-
|
158
|
+
source, path = parse_entry_spec(site, entry_spec)
|
144
159
|
prototype = {
|
145
160
|
'title' => Hx.make_default_title(site.options, path),
|
146
161
|
'author' => Hx.get_default_author(site.options),
|
147
162
|
'content' => ""
|
148
163
|
}
|
149
|
-
do_edit(site,
|
164
|
+
do_edit(site, source, path, prototype)
|
150
165
|
end
|
151
166
|
|
152
|
-
def self.
|
153
|
-
source = site
|
154
|
-
|
167
|
+
def self.cmd_list(site, entry_spec)
|
168
|
+
source, selector = parse_entry_pattern(site, entry_spec)
|
169
|
+
source.each_entry_path(selector) { |path| puts path }
|
170
|
+
end
|
155
171
|
|
172
|
+
def self.do_edit(site, source, path, prototype)
|
156
173
|
catch(:unchanged) do
|
157
174
|
begin
|
158
175
|
tempfile = Tempfile.new('hx-entry')
|
@@ -74,7 +74,7 @@ class LiquidTemplate
|
|
74
74
|
template_file = template_dir + "#{options[:template]}.liquid"
|
75
75
|
@template = Liquid::Template.parse(template_file.read)
|
76
76
|
@extension = options[:extension]
|
77
|
-
@
|
77
|
+
@content_type = options[:content_type]
|
78
78
|
@strip_extension_re = nil
|
79
79
|
@strip_extension_re = /\.#{Regexp.quote(@extension)}$/ if @extension
|
80
80
|
end
|
@@ -99,7 +99,7 @@ class LiquidTemplate
|
|
99
99
|
'entry' => entry
|
100
100
|
)
|
101
101
|
end
|
102
|
-
output_entry['
|
102
|
+
output_entry['content_type'] = @content_type if @content_type
|
103
103
|
if entry.has_key? 'updated'
|
104
104
|
output_entry['created'] = output_entry['updated'] = entry['updated']
|
105
105
|
end
|
data/lib/hx/path.rb
CHANGED
@@ -25,11 +25,6 @@ module Hx
|
|
25
25
|
module Path
|
26
26
|
|
27
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
28
|
def accept?(path)
|
34
29
|
raise NotImplementedError, "#{self.class}#accept? not implemented"
|
35
30
|
end
|
@@ -49,37 +44,25 @@ end
|
|
49
44
|
|
50
45
|
class All
|
51
46
|
include Selector
|
52
|
-
|
53
|
-
REGEXP = Regexp.new("^.*$")
|
54
|
-
|
55
|
-
def regexp ; REGEXP ; end
|
56
47
|
def accept?(path) ; true ; end
|
57
48
|
end
|
58
49
|
|
59
50
|
ALL = All.new
|
60
51
|
|
61
|
-
class
|
52
|
+
class Pattern
|
62
53
|
include Selector
|
63
54
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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)}$")
|
55
|
+
def initialize(tokens)
|
56
|
+
@regexp = Regexp.new("^#{tokens.map { |token|
|
57
|
+
case token
|
58
|
+
when :doublestar; '.*'
|
59
|
+
when :star; '[^/]*'
|
60
|
+
else; Regexp.quote(token)
|
61
|
+
end
|
62
|
+
}}$")
|
78
63
|
end
|
79
64
|
|
80
|
-
def accept?(path)
|
81
|
-
@value == path
|
82
|
-
end
|
65
|
+
def accept?(path) ; !!(path =~ @regexp) ; end
|
83
66
|
end
|
84
67
|
|
85
68
|
def self.parse_pattern(pattern_string)
|
@@ -91,78 +74,35 @@ def self.parse_pattern(pattern_string)
|
|
91
74
|
else; token
|
92
75
|
end
|
93
76
|
end
|
94
|
-
|
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
|
77
|
+
Pattern.new(tokens)
|
110
78
|
end
|
111
79
|
|
112
80
|
def self.literal(literal_string)
|
113
|
-
|
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
|
81
|
+
Pattern.new([literal_string])
|
132
82
|
end
|
133
83
|
|
134
84
|
module Connective
|
135
85
|
include Selector
|
136
86
|
|
137
|
-
attr_reader :prefix
|
138
|
-
attr_reader :suffix
|
139
|
-
|
140
87
|
def initialize(*selectors)
|
141
88
|
@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
89
|
end
|
161
90
|
end
|
162
91
|
|
163
92
|
class Conjunction
|
164
93
|
include Connective
|
165
94
|
|
95
|
+
def self.new(*selectors)
|
96
|
+
if selectors.any? { |s| All === s }
|
97
|
+
selectors.reject! { |s| All === s }
|
98
|
+
case selectors.size
|
99
|
+
when 0; return ALL
|
100
|
+
when 1; return selectors.first
|
101
|
+
end
|
102
|
+
end
|
103
|
+
super(*selectors)
|
104
|
+
end
|
105
|
+
|
166
106
|
def accept?(path)
|
167
107
|
@selectors.all? { |s| s.accept? path }
|
168
108
|
end
|
@@ -171,24 +111,8 @@ end
|
|
171
111
|
class Disjunction
|
172
112
|
include Connective
|
173
113
|
|
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
114
|
def accept?(path)
|
187
|
-
|
188
|
-
!!@regexp.match(path)
|
189
|
-
else
|
190
|
-
@selectors.any? { |s| s.accept? path }
|
191
|
-
end
|
115
|
+
@selectors.any? { |s| s.accept? path }
|
192
116
|
end
|
193
117
|
end
|
194
118
|
|
data/lib/hx/rack/application.rb
CHANGED
@@ -78,13 +78,13 @@ class Application
|
|
78
78
|
end
|
79
79
|
|
80
80
|
if entry
|
81
|
-
|
82
|
-
unless
|
81
|
+
content_type = entry['content_type']
|
82
|
+
unless content_type
|
83
83
|
effective_path =~ /(\.[^.]+)$/
|
84
|
-
|
84
|
+
content_type = ::Rack::Mime.mime_type($1 || '')
|
85
85
|
end
|
86
86
|
content = entry['content'].to_s
|
87
|
-
[200, {'Content-Type' =>
|
87
|
+
[200, {'Content-Type' => content_type}, [content]]
|
88
88
|
else
|
89
89
|
message = "#{env['SCRIPT_NAME']}#{path} not found"
|
90
90
|
[404, {'Content-Type' => "text/plain"}, [message]]
|
data/spec/rack_spec.rb
CHANGED
@@ -30,22 +30,22 @@ describe Hx::Rack::Application do
|
|
30
30
|
it "should infer content type from file extension by default" do
|
31
31
|
cases = { "html" => "text/html",
|
32
32
|
"jpeg" => "image/jpeg" }
|
33
|
-
for extension,
|
33
|
+
for extension, content_type in cases
|
34
34
|
path = "blah.#{extension}"
|
35
35
|
@input.add_entry(path, "")
|
36
36
|
response = @service.get("/#{path}", :lint => true, :fatal => true)
|
37
37
|
response.status.to_i.should == 200
|
38
|
-
response['Content-Type'].should ==
|
38
|
+
response['Content-Type'].should == content_type
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should allow entries to specify their mime type" do
|
43
43
|
path = "blah.html"
|
44
|
-
|
45
|
-
@input.add_entry(path, "", '
|
44
|
+
content_type = "junk/garbage"
|
45
|
+
@input.add_entry(path, "", 'content_type' => content_type)
|
46
46
|
response = @service.get("/#{path}", :lint => true, :fatal => true)
|
47
47
|
response.status.to_i.should == 200
|
48
|
-
response['Content-Type'].should ==
|
48
|
+
response['Content-Type'].should == content_type
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should redirect for directories with indices" do
|
data/spec/selector_spec.rb
CHANGED
@@ -7,72 +7,27 @@ describe Hx::Path::Pattern do
|
|
7
7
|
Hx::Path::Pattern.should < Hx::Path::Selector
|
8
8
|
end
|
9
9
|
|
10
|
-
it "should
|
11
|
-
|
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")
|
10
|
+
it "should accept or reject literal paths" do
|
11
|
+
pattern = Hx::Path.literal("foo/bar")
|
35
12
|
pattern.should accept("foo/bar")
|
36
13
|
pattern.should_not accept("foo/baz")
|
37
14
|
end
|
38
15
|
|
39
|
-
it "should
|
40
|
-
pattern = Hx::Path.parse_pattern("foo
|
41
|
-
pattern.
|
42
|
-
pattern.
|
43
|
-
pattern.
|
16
|
+
it "should match single path components with stars" do
|
17
|
+
pattern = Hx::Path.parse_pattern("foo/*")
|
18
|
+
pattern.should_not accept("baz/eek")
|
19
|
+
pattern.should accept("foo/bar")
|
20
|
+
pattern.should_not accept("foo/bar/baz")
|
21
|
+
end
|
44
22
|
|
45
|
-
|
46
|
-
pattern.
|
47
|
-
pattern.
|
48
|
-
pattern.
|
23
|
+
it "should match multiple path components with double stars" do
|
24
|
+
pattern = Hx::Path.parse_pattern("foo/**")
|
25
|
+
pattern.should_not accept("baz/eek")
|
26
|
+
pattern.should accept("foo/bar")
|
27
|
+
pattern.should accept("foo/bar/baz")
|
49
28
|
end
|
50
29
|
end
|
51
30
|
|
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
31
|
describe "Hx::Path::Selector disjunctions" do
|
77
32
|
it "should be possible" do
|
78
33
|
filters = ["foo/bar", "abcdefg"].map { |p| Hx::Path.parse_pattern(p) }
|
@@ -87,17 +42,6 @@ describe "Hx::Path::Selector disjunctions" do
|
|
87
42
|
filter.should accept("abcdefg")
|
88
43
|
filter.should_not accept("hoge")
|
89
44
|
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
45
|
end
|
102
46
|
|
103
47
|
describe "negated Hx::Path::Selectors" do
|
@@ -113,11 +57,6 @@ describe "negated Hx::Path::Selectors" do
|
|
113
57
|
@pattern.should_not accept("foobar")
|
114
58
|
@pattern.should accept("hoge")
|
115
59
|
end
|
116
|
-
|
117
|
-
it "should have empty prefix and suffix" do
|
118
|
-
@pattern.prefix.should == ""
|
119
|
-
@pattern.suffix.should == ""
|
120
|
-
end
|
121
60
|
end
|
122
61
|
|
123
62
|
describe "Hx::Path::Selector conjunctions" do
|
@@ -137,14 +76,10 @@ describe "Hx::Path::Selector conjunctions" do
|
|
137
76
|
filter.should_not accept("rebar")
|
138
77
|
end
|
139
78
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
filter.prefix.should == test_case[:prefix]
|
146
|
-
filter.suffix.should == test_case[:suffix]
|
147
|
-
end
|
148
|
-
end.call(test_case_outer)
|
79
|
+
it "should optimize use of ALL" do
|
80
|
+
filter = Hx::Path.parse_pattern("foo")
|
81
|
+
(filter & Hx::Path::ALL).should equal(filter)
|
82
|
+
(Hx::Path::ALL & filter).should equal(filter)
|
83
|
+
(Hx::Path::ALL & Hx::Path::ALL).should equal(Hx::Path::ALL)
|
149
84
|
end
|
150
85
|
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.8.
|
4
|
+
version: 0.8.3
|
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-05-29 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|