hawkins 0.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +31 -6
- data/LICENSE.txt +2 -0
- data/README.md +43 -14
- data/Rakefile +13 -10
- data/hawkins.gemspec +7 -11
- data/js/WebSocketMain.swf +0 -0
- data/js/livereload.js +1055 -0
- data/js/swfobject.js +4 -0
- data/js/web_socket.js +379 -0
- data/lib/hawkins.rb +6 -40
- data/lib/hawkins/liveserve.rb +250 -0
- data/lib/hawkins/post.rb +86 -0
- data/lib/hawkins/servlet.rb +154 -0
- data/lib/hawkins/version.rb +1 -1
- data/lib/hawkins/websockets.rb +160 -0
- data/lib/mime.types +800 -0
- data/test/resources/test.crt +18 -0
- data/test/resources/test.key +28 -0
- data/test/spec_helper.rb +13 -10
- data/test/test_liveserve.rb +166 -0
- data/test/test_post.rb +171 -0
- metadata +50 -94
- data/lib/hawkins/cli.rb +0 -190
- data/lib/hawkins/guard.rb +0 -268
- data/lib/hawkins/isolation.rb +0 -116
- data/test/test_hawkins.rb +0 -134
data/lib/hawkins/isolation.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require 'rack'
|
3
|
-
require 'safe_yaml/load'
|
4
|
-
require 'set'
|
5
|
-
|
6
|
-
module Hawkins
|
7
|
-
class IsolationInjector
|
8
|
-
attr_reader :site_root
|
9
|
-
attr_reader :isolation_file
|
10
|
-
|
11
|
-
def initialize(options={})
|
12
|
-
@options = options
|
13
|
-
@site_root = @options[:site_root] || Jekyll.configuration({})['destination']
|
14
|
-
@isolation_file = @options[:isolation_file] || Hawkins::ISOLATION_FILE
|
15
|
-
SafeYAML::OPTIONS[:default_mode] = :safe
|
16
|
-
end
|
17
|
-
|
18
|
-
def call(env)
|
19
|
-
req = Rack::Request.new(env)
|
20
|
-
path = Pathname.new(req.path_info).relative_path_from(Pathname.new('/'))
|
21
|
-
path = File.join(site_root, path.to_s)
|
22
|
-
|
23
|
-
path = File.join(path, "index.html") if File.directory?(path)
|
24
|
-
path = Pathname.new(path).cleanpath.to_s
|
25
|
-
|
26
|
-
files = Dir[File.join(site_root, "**/*")]
|
27
|
-
if files.include?(path)
|
28
|
-
mime = mime(path)
|
29
|
-
file = file_info(path)
|
30
|
-
body = file[:body]
|
31
|
-
time = file[:time]
|
32
|
-
hdrs = {'Last-Modified' => time}
|
33
|
-
|
34
|
-
if time == req.env['HTTP_IF_MODIFIED_SINCE']
|
35
|
-
[304, hdrs, []]
|
36
|
-
else
|
37
|
-
hdrs.update(
|
38
|
-
'Content-length' => body.bytesize.to_s,
|
39
|
-
'Content-Type' => mime
|
40
|
-
)
|
41
|
-
[200, hdrs, [body]]
|
42
|
-
end
|
43
|
-
else
|
44
|
-
handle_404(req, path)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def handle_404(req, true_path)
|
49
|
-
if File.exist?(isolation_file)
|
50
|
-
file = true_path
|
51
|
-
# Use a wildcard since the origin file could be anything
|
52
|
-
file = "#{File.basename(file, File.extname(file))}.*".force_encoding('utf-8')
|
53
|
-
|
54
|
-
config = SafeYAML.load_file(isolation_file)
|
55
|
-
|
56
|
-
file_set = Set.new(config['include'])
|
57
|
-
|
58
|
-
# Prevent loops. If it's already in 'include'
|
59
|
-
# then we've gone through here before.
|
60
|
-
return static_error if file_set.include?(file)
|
61
|
-
|
62
|
-
config['include'] = file_set.add(file).to_a
|
63
|
-
|
64
|
-
File.open(isolation_file, 'w') do |f|
|
65
|
-
YAML.dump(config, f)
|
66
|
-
end
|
67
|
-
|
68
|
-
response = <<-PAGE.gsub(/^\s*/, '')
|
69
|
-
<!DOCTYPE HTML>
|
70
|
-
<html lang="en-US">
|
71
|
-
<head>
|
72
|
-
<meta charset="UTF-8">
|
73
|
-
<title>Rendering #{req.path_info}</title>
|
74
|
-
</head>
|
75
|
-
<body>
|
76
|
-
<h1>Hold on while I render that page for you!</h1>
|
77
|
-
</body>
|
78
|
-
PAGE
|
79
|
-
|
80
|
-
headers = {}
|
81
|
-
headers['Content-Length'] = response.bytesize.to_s
|
82
|
-
headers['Content-Type'] = 'text/html'
|
83
|
-
headers['Connection'] = 'keep-alive'
|
84
|
-
[200, headers, [response]]
|
85
|
-
else
|
86
|
-
static_error
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def static_error
|
91
|
-
error_page = File.join(site_root, "404.html")
|
92
|
-
if File.exist?(error_page)
|
93
|
-
body = file_info(error_page)[:body]
|
94
|
-
mime = mime(error_page)
|
95
|
-
else
|
96
|
-
body = "Not found"
|
97
|
-
mime = "text/plain"
|
98
|
-
end
|
99
|
-
[404, {"Content-Type" => mime, "Content-length" => body.bytesize.to_s}, [body]]
|
100
|
-
end
|
101
|
-
|
102
|
-
def mime(path_info)
|
103
|
-
Rack::Mime.mime_type(File.extname(path_info))
|
104
|
-
end
|
105
|
-
|
106
|
-
def file_info(path)
|
107
|
-
File.open(path, 'r') do |f|
|
108
|
-
{
|
109
|
-
:body => f.read,
|
110
|
-
:time => f.mtime.httpdate,
|
111
|
-
:expand_path => path
|
112
|
-
}
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
data/test/test_hawkins.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
module Hawkins
|
2
|
-
RSpec.describe "Hawkins" do
|
3
|
-
context "when creating a post" do
|
4
|
-
before(:each) do
|
5
|
-
default_config = Jekyll::Configuration[Jekyll::Configuration::DEFAULTS]
|
6
|
-
allow_any_instance_of(Jekyll::Configuration).to receive(:[]).and_return(default_config)
|
7
|
-
allow_any_instance_of(Jekyll::Configuration).to receive(:config_files).and_return([])
|
8
|
-
allow_any_instance_of(Jekyll::Configuration).to receive(:read_config_files).and_return(default_config)
|
9
|
-
end
|
10
|
-
|
11
|
-
let(:date) do
|
12
|
-
Time.now.strftime('%Y-%m-%d')
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:cli_spy) do
|
16
|
-
spy('Cli')
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'fails on a bad post date' do
|
20
|
-
_, err = capture_io do
|
21
|
-
expect do
|
22
|
-
Cli.start(%w(post --date BAD_DATE title))
|
23
|
-
end.to raise_error(SystemExit)
|
24
|
-
end
|
25
|
-
|
26
|
-
expect(err).to match(/Could not parse/)
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'fails on a missing title' do
|
30
|
-
_, err = capture_io do
|
31
|
-
expect do
|
32
|
-
Cli.start(%w(post))
|
33
|
-
end.to raise_error(SystemExit)
|
34
|
-
end
|
35
|
-
expect(err).to match(/called with no arguments/)
|
36
|
-
end
|
37
|
-
|
38
|
-
# TODO There is a lot of redundancy here. There's got to be a better way.
|
39
|
-
# Look at http://betterspecs.org for ideas.
|
40
|
-
it 'uses a provided date' do
|
41
|
-
title = "Party Like It's 1999"
|
42
|
-
expected_body =<<-BODY.gsub(/^\s*/,'')
|
43
|
-
---
|
44
|
-
title: #{title}
|
45
|
-
---
|
46
|
-
BODY
|
47
|
-
expected_file="_posts/1999-12-31-#{title.to_url}.md"
|
48
|
-
# Required to keep Thor from printing warning about undescribed commands.
|
49
|
-
cli_spy.no_commands do
|
50
|
-
expect(cli_spy).to receive(:empty_directory)
|
51
|
-
expect(cli_spy).to receive(:create_file).with(expected_file, expected_body)
|
52
|
-
expect(cli_spy).to receive(:exec)
|
53
|
-
end
|
54
|
-
|
55
|
-
cli_spy.start(%W(post --date 1999-12-31 #{title}))
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'uses today as the default date' do
|
59
|
-
title = "Raspberry Beret"
|
60
|
-
expected_body =<<-BODY.gsub(/^\s*/,'')
|
61
|
-
---
|
62
|
-
title: #{title}
|
63
|
-
---
|
64
|
-
BODY
|
65
|
-
expected_file="_posts/#{date}-#{title.to_url}.md"
|
66
|
-
cli_spy.no_commands do
|
67
|
-
expect(cli_spy).to receive(:empty_directory)
|
68
|
-
expect(cli_spy).to receive(:create_file).with(expected_file, expected_body)
|
69
|
-
expect(cli_spy).to receive(:exec)
|
70
|
-
end
|
71
|
-
|
72
|
-
cli_spy.start(%W(post #{title}))
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'uses a provided editor' do
|
76
|
-
title = "Little Red Corvette"
|
77
|
-
expected_file="_posts/#{date}-#{title.to_url}.md"
|
78
|
-
cli_spy.no_commands do
|
79
|
-
expect(cli_spy).to receive(:empty_directory)
|
80
|
-
expect(cli_spy).to receive(:create_file).with(expected_file, expected_body)
|
81
|
-
expect(cli_spy).to receive(:exec).with('foo', expected_file)
|
82
|
-
end
|
83
|
-
|
84
|
-
cli_spy.start(%W(post --editor foo #{title}))
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'uses the editor from the environment' do
|
88
|
-
title = "Let's Go Crazy"
|
89
|
-
expected_file="_posts/#{date}-#{title.to_url}.md"
|
90
|
-
|
91
|
-
stub_const("ENV", ENV.to_h.tap { |h| h['VISUAL'] = 'default' })
|
92
|
-
cli_spy.no_commands do
|
93
|
-
expect(cli_spy).to receive(:empty_directory)
|
94
|
-
expect(cli_spy).to receive(:create_file)
|
95
|
-
expect(cli_spy).to receive(:exec).with('default', expected_file)
|
96
|
-
end
|
97
|
-
|
98
|
-
cli_spy.start(%W(post #{title}))
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'sets correct vim options' do
|
102
|
-
title = "When Doves Cry"
|
103
|
-
expected_file="_posts/#{date}-#{title.to_url}.md"
|
104
|
-
|
105
|
-
['gvim', 'vim'].each do |editor|
|
106
|
-
stub_const("ENV", ENV.to_h.tap { |h| h['VISUAL'] = editor })
|
107
|
-
cli_spy.no_commands do
|
108
|
-
expect(cli_spy).to receive(:empty_directory)
|
109
|
-
expect(cli_spy).to receive(:create_file)
|
110
|
-
expect(cli_spy).to receive(:exec).with(editor, '+', expected_file)
|
111
|
-
end
|
112
|
-
|
113
|
-
cli_spy.start(%W(post #{title}))
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'sets correct emacs options' do
|
118
|
-
title = "Purple Rain"
|
119
|
-
expected_file="_posts/#{date}-#{title.to_url}.md"
|
120
|
-
|
121
|
-
['xemacs', 'emacs'].each do |editor|
|
122
|
-
stub_const("ENV", ENV.to_h.tap { |h| h['VISUAL'] = editor })
|
123
|
-
cli_spy.no_commands do
|
124
|
-
expect(cli_spy).to receive(:empty_directory)
|
125
|
-
expect(cli_spy).to receive(:create_file)
|
126
|
-
expect(cli_spy).to receive(:exec).with(editor, '+3', expected_file)
|
127
|
-
end
|
128
|
-
|
129
|
-
cli_spy.start(%W(post #{title}))
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|