hawkins 0.1.0 → 2.0.0
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.
- 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
|