smeagol 0.5.9 → 0.6.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.
Files changed (59) hide show
  1. data/.ruby +80 -0
  2. data/.yardopts +9 -0
  3. data/HISTORY.md +147 -0
  4. data/LICENSE.txt +30 -0
  5. data/README.md +132 -26
  6. data/bin/smeagol +9 -39
  7. data/bin/smeagol-init +3 -0
  8. data/bin/smeagol-preview +4 -0
  9. data/bin/smeagol-serve +4 -0
  10. data/bin/smeagol-update +4 -0
  11. data/bin/smeagold +1 -4
  12. data/lib/smeagol.rb +77 -6
  13. data/lib/smeagol/app.rb +121 -75
  14. data/lib/smeagol/cache.rb +43 -24
  15. data/lib/smeagol/cli.rb +166 -0
  16. data/lib/smeagol/config.rb +154 -0
  17. data/lib/smeagol/console.rb +369 -0
  18. data/lib/smeagol/controller.rb +275 -0
  19. data/lib/smeagol/core_ext.rb +12 -0
  20. data/lib/smeagol/gollum/blob_entry.rb +17 -0
  21. data/lib/smeagol/gollum/file.rb +44 -0
  22. data/lib/smeagol/gollum/page.rb +47 -0
  23. data/lib/smeagol/gollum/wiki.rb +31 -0
  24. data/lib/smeagol/helpers/rss.rb +96 -0
  25. data/lib/smeagol/helpers/toc.rb +69 -0
  26. data/lib/smeagol/public/assets/smeagol/gollum.css +716 -0
  27. data/lib/smeagol/public/{smeagol → assets/smeagol}/html5.js +0 -0
  28. data/lib/smeagol/public/{smeagol → assets/smeagol}/pygment.css +0 -0
  29. data/lib/smeagol/public/assets/smeagol/template.css +631 -0
  30. data/lib/smeagol/repository.rb +85 -0
  31. data/lib/smeagol/settings.rb +302 -0
  32. data/lib/smeagol/templates/layouts/page.mustache +19 -0
  33. data/lib/smeagol/templates/layouts/versions.mustache +16 -0
  34. data/lib/smeagol/templates/partials/footer.mustache +17 -0
  35. data/lib/smeagol/templates/partials/header.mustache +47 -0
  36. data/lib/smeagol/templates/settings.yml +64 -0
  37. data/lib/smeagol/version.rb +1 -1
  38. data/lib/smeagol/views/base.rb +188 -27
  39. data/lib/smeagol/views/form.rb +56 -0
  40. data/lib/smeagol/views/page.rb +126 -25
  41. data/lib/smeagol/views/post.rb +51 -0
  42. data/lib/smeagol/views/versions.rb +20 -6
  43. data/lib/smeagol/wiki.rb +25 -45
  44. data/test/helper.rb +72 -8
  45. data/test/test_app.rb +57 -0
  46. data/test/test_cache.rb +10 -11
  47. data/test/test_init.rb +27 -0
  48. data/test/test_update.rb +20 -0
  49. data/test/test_wiki.rb +13 -10
  50. metadata +142 -216
  51. data/bin/smeagol-static +0 -115
  52. data/lib/file.rb +0 -10
  53. data/lib/smeagol/hash.rb +0 -13
  54. data/lib/smeagol/option_parser.rb +0 -138
  55. data/lib/smeagol/public/smeagol/main.css +0 -234
  56. data/lib/smeagol/templates/page.mustache +0 -58
  57. data/lib/smeagol/templates/versions.mustache +0 -50
  58. data/test/test_file.rb +0 -12
  59. data/test/test_hash.rb +0 -18
@@ -1,115 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- require 'mustache'
5
- require 'optparse'
6
- require 'smeagol'
7
-
8
- class Static
9
- def initialize(wiki)
10
- @wiki = wiki
11
- @directory = []
12
- end
13
-
14
- def template
15
- if File.exists?("#{@wiki.path}/page.mustache")
16
- IO.read("#{@wiki.path}/page.mustache")
17
- else
18
- IO.read(File.join(File.dirname(__FILE__), "../lib/smeagol/templates/page.mustache"))
19
- end
20
- end
21
-
22
- def current_directory
23
- @directory.last
24
- end
25
-
26
- def directory_pop
27
- @directory.pop()
28
- end
29
-
30
- def directory_push(dir)
31
- if @directory.empty?
32
- @directory << dir
33
- else
34
- @directory << "#{current_directory}/#{dir}"
35
- end
36
-
37
- if not File.directory?(current_directory)
38
- Dir::mkdir(current_directory)
39
- end
40
- end
41
-
42
- def build_tree(tree)
43
- tree.contents.each do |item|
44
- if item.class == Grit::Tree
45
- directory_push(item.name)
46
- build_tree(item)
47
- directory_pop()
48
- else
49
- build_blob(item)
50
- end
51
- end
52
- end
53
-
54
- def build_blob(blob)
55
- if name = @wiki.page_class.valid_page_name?(blob.name)
56
- page = @wiki.page(name)
57
-
58
- if name != 'Home'
59
- directory_push(name)
60
- end
61
-
62
- File.open("#{current_directory}/index.html", 'w') do |f|
63
- f.write(Mustache.render(template, Smeagol::Views::Page.new(page)))
64
- end
65
-
66
- if name != 'Home'
67
- directory_pop
68
- end
69
- else
70
- File.open("#{current_directory}/#{blob.name}", 'w') do |f|
71
- f.write(blob.data)
72
- end
73
- end
74
- end
75
-
76
- def build(directory)
77
- directory_push(directory)
78
- build_tree(@wiki.repo.tree)
79
- directory_pop
80
- end
81
- end
82
-
83
- options = {}
84
- optparse = OptionParser.new do |opts|
85
- opts.banner = "usage: smeagol-static [options] [path]"
86
-
87
- opts.on('-h', '--help', 'Displays this usage screen') do
88
- puts optparse
89
- exit
90
- end
91
-
92
- opts.on('-b', '--build DIRECTORY') do |dir|
93
- options[:build_dir] = dir
94
- end
95
- end
96
-
97
- begin
98
- optparse.parse!
99
- rescue OptionParser::InvalidOption
100
- puts optparse
101
- exit 1
102
- end
103
-
104
- if ARGV.first
105
- options[:repo] = ARGV.first
106
- else
107
- options[:repo] = Dir.pwd
108
- end
109
-
110
- if not options.key?(:build_dir)
111
- options[:build_dir] = options[:repo] + "/build"
112
- end
113
-
114
- static = Static.new(Smeagol::Wiki.new(options[:repo]))
115
- static.build(options[:build_dir])
@@ -1,10 +0,0 @@
1
- class File
2
- # Removes all references to parent directories (../) in a path.
3
- #
4
- # path - The path to sanitize.
5
- #
6
- # Returns a clean, pristine path.
7
- def self.sanitize_path(path)
8
- path.gsub(/\.\.(?=$|\/)/, '') unless path.nil?
9
- end
10
- end
@@ -1,13 +0,0 @@
1
- class Hash
2
- # Recursively converts a Hash object to an OpenStruct object.
3
- #
4
- # Returns a copy of the hash as an OpenStruct.
5
- def to_ostruct()
6
- struct = OpenStruct.new(self.clone())
7
- each do |k, v|
8
- struct.__send__("#{k}=", v.to_ostruct()) if v.is_a?(Hash)
9
- struct.__send__(k).map! {|x| x.is_a?(Hash) ? x.to_ostruct() : x} if v.is_a?(Array)
10
- end
11
- return struct
12
- end
13
- end
@@ -1,138 +0,0 @@
1
- module Smeagol
2
- class OptionParser
3
- # Parses the command line options.
4
- #
5
- # args - The arguments to parse. Typically use `ARGV`.
6
- #
7
- # Returns an OpenStruct of the options.
8
- def self.parse(args)
9
- # Set parse options
10
- secret = nil
11
- options = {}
12
- parser = ::OptionParser.new do |parser|
13
- parser.banner = 'usage: smeagol [OPTIONS] [PATH]\n\n'
14
-
15
- parser.on('--port [PORT]', 'Bind port (default 4567).') do |port|
16
- options['port'] = port.to_i
17
- end
18
-
19
- parser.on('--git [GIT]', 'Path to Git binary.') do |path|
20
- options['git'] = path
21
- end
22
-
23
- parser.on('-c', '--config [PATH]', 'Loads the config file. (default /etc/smeagol/config.yml)') do |path|
24
- puts "Cannot find configuration file: #{path}" unless File.exists?(path)
25
- puts "Cannot read configuration file: #{path}" unless File.readable?(path)
26
- options['config_path'] = path
27
- end
28
-
29
- parser.on('--auto-update', 'Updates the repository on a daily basis.') do |flag|
30
- options['auto_update'] = flag
31
- end
32
-
33
- parser.on('--[no-]cache', 'Enables page caching.') do |flag|
34
- options['cache_enabled'] = flag
35
- end
36
-
37
- parser.on('--secret [KEY]', 'Specifies the secret key used to update.') do |str|
38
- secret = str
39
- end
40
-
41
- parser.on('-v', '--version', 'Display current version.') do
42
- puts "Smeagol #{Smeagol::VERSION}"
43
- exit 0
44
- end
45
- end
46
-
47
- # Read command line options into `options` hash
48
- begin
49
- parser.parse!
50
- rescue ::OptionParser::InvalidOption
51
- puts "smeagol: #{$!.message}"
52
- puts "smeagol: try 'smeagol --help' for more information"
53
- exit
54
- end
55
-
56
- # Load config
57
- config_path = options['config_path'] || '/etc/smeagol/config.yml'
58
- config = load_config(config_path)
59
- opts = default_options.merge(config).merge(options)
60
- opts = opts.to_ostruct()
61
-
62
- # Attempt to find the git binary
63
- update_git_path(opts)
64
-
65
- # Append repositories from the command line.
66
- opts.repositories ||= []
67
- if !args.first.nil?
68
- opts.repositories.unshift({:path => args.first}.to_ostruct)
69
- end
70
-
71
- # Set repository to present working directory if no paths specified.
72
- if opts.repositories.empty?
73
- opts.repositories = [{:path => Dir.pwd}.to_ostruct]
74
- end
75
-
76
- # Set secret on default repository if passed in.
77
- opts.repositories.first.secret = secret unless secret.nil?
78
-
79
- # Merge all options
80
- return opts
81
- end
82
-
83
-
84
- ###########################################################################
85
- #
86
- # Private Methods
87
- #
88
- ###########################################################################
89
-
90
- private
91
-
92
- # The default options for Smeagol.
93
- def self.default_options
94
- options = Hash.new
95
- options['port'] = 4567
96
- options['auto_update'] = false
97
- options['cache_enabled'] = true
98
- options
99
- end
100
-
101
- # Loads a configuration file.
102
- #
103
- # Returns a hash of options from the config file.
104
- def self.load_config(path)
105
- config = {}
106
-
107
- if File.exists?(path)
108
- # Notify the user if the config file exists but is not readable.
109
- if !File.readable?(path)
110
- puts "Config file not readable: #{path}"
111
- exit
112
- end
113
-
114
- config = YAML.load(IO.read(path))
115
- end
116
-
117
- return config
118
- end
119
-
120
- # Locates the git binary in common places in the file system.
121
- def self.update_git_path(options)
122
- if options.git.nil?
123
- ['/usr/bin', '/usr/sbin', '/usr/local/bin', '/opt/local/bin'].each do |path|
124
- file = "#{path}/git"
125
- options.git = file if File.executable?(file)
126
- break if options.git
127
- end
128
- end
129
-
130
- # Alert user that updates are unavailable if git is not found
131
- if options.git.nil? || !File.executable?(options.git)
132
- puts "warning: git executable could not be found."
133
- else
134
- puts "git found: #{options.git}"
135
- end
136
- end
137
- end
138
- end
@@ -1,234 +0,0 @@
1
- /* Reset from: http://meyerweb.com/eric/tools/css/reset/ */
2
- html, body, div, span, applet, object, iframe,
3
- h1, h2, h3, h4, h5, h6, p, blockquote, pre,
4
- a, abbr, acronym, address, big, cite, code,
5
- del, dfn, em, font, img, ins, kbd, q, s, samp,
6
- small, strike, strong, sub, sup, tt, var,
7
- b, u, i, center,
8
- dl, dt, dd, ol, ul, li,
9
- fieldset, form, label, legend,
10
- table, caption, tbody, tfoot, thead, tr, th, td {
11
- margin: 0;
12
- padding: 0;
13
- border: 0;
14
- outline: 0;
15
- font-size: 100%;
16
- vertical-align: baseline;
17
- background: transparent;
18
- }
19
- body {
20
- line-height: 1;
21
- }
22
- ol, ul {
23
- list-style: none;
24
- }
25
- blockquote, q {
26
- quotes: none;
27
- }
28
- blockquote:before, blockquote:after,
29
- q:before, q:after {
30
- content: '';
31
- content: none;
32
- }
33
-
34
- :focus {
35
- outline: 0;
36
- }
37
-
38
- ins {
39
- text-decoration: none;
40
- }
41
- del {
42
- text-decoration: line-through;
43
- }
44
-
45
- table {
46
- border-collapse: collapse;
47
- border-spacing: 0;
48
- }
49
-
50
-
51
-
52
- /* Main styles */
53
- body {
54
- font: normal normal normal 13.34px/normal helvetica, arial, sans-serif;
55
- font-size: 14px;
56
- line-height: 1.4em;
57
- }
58
-
59
- a {
60
- color: #4183C4;
61
- text-decoration: none;
62
- }
63
-
64
- a:hover {
65
- text-decoration: underline;
66
- }
67
-
68
-
69
- header {
70
- display: block;
71
- }
72
-
73
- footer {
74
- display: block;
75
- border-top: 2px solid #ccc;
76
- padding-top: 1px;
77
- margin-top: 2.5em;
78
- margin-bottom: 2em;
79
- }
80
-
81
- nav {
82
- display: block;
83
- border-top: 1px solid #ccc;
84
- border-bottom: 1px solid #ccc;
85
- margin-bottom: 1.5em;
86
- }
87
-
88
- nav ul {
89
- padding: 2px 2px 2px 2px;
90
- margin: 3px 0px 0px;
91
- white-space: nowrap;
92
- }
93
-
94
- nav ul li {
95
- display: inline;
96
- list-style-type: none;
97
- padding: 0px 35px 0px 0px;
98
- }
99
-
100
- nav ul li a {
101
- color: #333;
102
- font-weight: bold;
103
- text-decoration: none;
104
- }
105
-
106
- nav ul li a:hover {
107
- color: black;
108
- }
109
-
110
-
111
- .tagline {
112
- font-style: italic;
113
- }
114
-
115
- #container {
116
- margin-left: auto;
117
- margin-right: auto;
118
- width: 650px;
119
- }
120
-
121
- h1 {
122
- font-size: 250%;
123
- margin-top: 1em;
124
- margin-bottom: 0.3em;
125
- }
126
-
127
- article h1 {
128
- font-size: 150%;
129
- margin-bottom: 0.7em;
130
- }
131
-
132
- #content {
133
- color: #333;
134
- }
135
-
136
- #content h1 {
137
- color: black;
138
- border-top: 4px solid #aaa;
139
- margin-top: 1.5em;
140
- padding-top: 0.5em;
141
- }
142
-
143
- #content h2 {
144
- font-size: 135%;
145
- color: black;
146
- border-top: 4px solid #e0e0e0;
147
- margin-top: 1.5em;
148
- padding-top: 0.5em;
149
- }
150
-
151
- #content h3 {
152
- font-size: 110%;
153
- margin-top:1.25em;
154
- margin-bottom:0.4em;
155
- font-size: 1.17em;
156
- }
157
-
158
- #content p {
159
- line-height: 1.5em;
160
- margin: 0.4em 0em 1em 0em;
161
- }
162
-
163
- #content ol {
164
- padding: 0px;
165
- margin: 1em 0px 1em 2em;
166
- display: block;
167
- list-style-type: decimal;
168
- }
169
-
170
- #content ul {
171
- padding: 0px;
172
- margin: 1em 0px 1em 2em;
173
- display: block;
174
- list-style-type: disc;
175
- }
176
-
177
- #content li {
178
- margin-bottom: 0.5em;
179
- margin-top: 0.5em;
180
- }
181
-
182
- pre {
183
- line-height: 1.5em;
184
- margin: 1em 0px;
185
- overflow: auto;
186
- padding: 0.5em;
187
- }
188
-
189
- code {
190
- padding: 0px 0.2em;
191
- }
192
-
193
- pre, code {
194
- background-color: ghostWhite;
195
- border: 1px solid #ddd;
196
- color: #444;
197
- font-size: 12px;
198
- font: normal normal normal 12px/normal Monaco, 'Courier New', monospace;
199
- }
200
-
201
- pre > code {
202
- border:none !important;
203
- }
204
-
205
- small {
206
- font-size: 80%;
207
- }
208
-
209
- span.frame{
210
- display:block;
211
- overflow:hidden;
212
- }
213
-
214
- span.frame > span{
215
- border: 1px solid #ddd;
216
- display: block;
217
- overflow: hidden;
218
- float: left;
219
- margin: 13px 0 0;
220
- padding: 7px;
221
- width:auto;
222
- }
223
-
224
- span.frame span img{
225
- display: block;
226
- float: left;
227
- }
228
-
229
- span.frame span span{
230
- clear: both;
231
- color: #333;
232
- display: block;
233
- padding:5px 0 0;
234
- }