smeagol 0.5.9 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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
- }