monad 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. data/CONTRIBUTING.md +68 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE +21 -0
  4. data/README.md +88 -0
  5. data/Rakefile +136 -0
  6. data/bin/monad +102 -0
  7. data/cucumber.yml +3 -0
  8. data/features/create_sites.feature +112 -0
  9. data/features/data_sources.feature +76 -0
  10. data/features/drafts.feature +25 -0
  11. data/features/embed_filters.feature +60 -0
  12. data/features/markdown.feature +30 -0
  13. data/features/pagination.feature +54 -0
  14. data/features/permalinks.feature +65 -0
  15. data/features/post_data.feature +214 -0
  16. data/features/site_configuration.feature +206 -0
  17. data/features/site_data.feature +101 -0
  18. data/features/step_definitions/monad_steps.rb +175 -0
  19. data/features/support/env.rb +25 -0
  20. data/lib/monad.rb +90 -0
  21. data/lib/monad/command.rb +27 -0
  22. data/lib/monad/commands/build.rb +64 -0
  23. data/lib/monad/commands/doctor.rb +29 -0
  24. data/lib/monad/commands/new.rb +50 -0
  25. data/lib/monad/commands/serve.rb +33 -0
  26. data/lib/monad/configuration.rb +183 -0
  27. data/lib/monad/converter.rb +48 -0
  28. data/lib/monad/converters/identity.rb +21 -0
  29. data/lib/monad/converters/markdown.rb +43 -0
  30. data/lib/monad/converters/markdown/kramdown_parser.rb +44 -0
  31. data/lib/monad/converters/markdown/maruku_parser.rb +47 -0
  32. data/lib/monad/converters/markdown/rdiscount_parser.rb +35 -0
  33. data/lib/monad/converters/markdown/redcarpet_parser.rb +70 -0
  34. data/lib/monad/converters/textile.rb +50 -0
  35. data/lib/monad/convertible.rb +152 -0
  36. data/lib/monad/core_ext.rb +68 -0
  37. data/lib/monad/deprecator.rb +32 -0
  38. data/lib/monad/draft.rb +35 -0
  39. data/lib/monad/drivers/json_driver.rb +39 -0
  40. data/lib/monad/drivers/yaml_driver.rb +23 -0
  41. data/lib/monad/errors.rb +4 -0
  42. data/lib/monad/filters.rb +154 -0
  43. data/lib/monad/generator.rb +4 -0
  44. data/lib/monad/generators/pagination.rb +143 -0
  45. data/lib/monad/layout.rb +42 -0
  46. data/lib/monad/logger.rb +54 -0
  47. data/lib/monad/mime.types +85 -0
  48. data/lib/monad/page.rb +163 -0
  49. data/lib/monad/plugin.rb +75 -0
  50. data/lib/monad/post.rb +377 -0
  51. data/lib/monad/site.rb +455 -0
  52. data/lib/monad/static_file.rb +70 -0
  53. data/lib/monad/tags/gist.rb +30 -0
  54. data/lib/monad/tags/highlight.rb +85 -0
  55. data/lib/monad/tags/include.rb +37 -0
  56. data/lib/monad/tags/post_url.rb +61 -0
  57. data/lib/site_template/.gitignore +1 -0
  58. data/lib/site_template/_config.yml +2 -0
  59. data/lib/site_template/_layouts/default.html +46 -0
  60. data/lib/site_template/_layouts/post.html +9 -0
  61. data/lib/site_template/_posts/0000-00-00-welcome-to-monad.markdown.erb +24 -0
  62. data/lib/site_template/css/main.css +165 -0
  63. data/lib/site_template/css/syntax.css +60 -0
  64. data/lib/site_template/index.html +13 -0
  65. data/monad.gemspec +197 -0
  66. data/script/bootstrap +2 -0
  67. data/test/fixtures/broken_front_matter1.erb +5 -0
  68. data/test/fixtures/broken_front_matter2.erb +4 -0
  69. data/test/fixtures/broken_front_matter3.erb +7 -0
  70. data/test/fixtures/exploit_front_matter.erb +4 -0
  71. data/test/fixtures/front_matter.erb +4 -0
  72. data/test/fixtures/members.yaml +7 -0
  73. data/test/helper.rb +62 -0
  74. data/test/source/.htaccess +8 -0
  75. data/test/source/_includes/sig.markdown +3 -0
  76. data/test/source/_layouts/default.html +27 -0
  77. data/test/source/_layouts/simple.html +1 -0
  78. data/test/source/_plugins/dummy.rb +8 -0
  79. data/test/source/_posts/2008-02-02-not-published.textile +8 -0
  80. data/test/source/_posts/2008-02-02-published.textile +8 -0
  81. data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
  82. data/test/source/_posts/2008-11-21-complex.textile +8 -0
  83. data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
  84. data/test/source/_posts/2008-12-13-include.markdown +8 -0
  85. data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
  86. data/test/source/_posts/2009-01-27-categories.textile +7 -0
  87. data/test/source/_posts/2009-01-27-category.textile +7 -0
  88. data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
  89. data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
  90. data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
  91. data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
  92. data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
  93. data/test/source/_posts/2009-05-18-tag.textile +6 -0
  94. data/test/source/_posts/2009-05-18-tags.textile +9 -0
  95. data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
  96. data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
  97. data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
  98. data/test/source/_posts/2010-01-09-date-override.textile +7 -0
  99. data/test/source/_posts/2010-01-09-time-override.textile +7 -0
  100. data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
  101. data/test/source/_posts/2010-01-16-override-data.textile +4 -0
  102. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  103. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  104. data/test/source/_posts/2013-01-02-post-excerpt.markdown +14 -0
  105. data/test/source/_posts/2013-01-12-nil-layout.textile +6 -0
  106. data/test/source/_posts/2013-01-12-no-layout.textile +5 -0
  107. data/test/source/_posts/2013-03-19-not-a-post.markdown/.gitkeep +0 -0
  108. data/test/source/_posts/2013-04-11-custom-excerpt.markdown +10 -0
  109. data/test/source/_posts/2013-05-10-number-category.textile +7 -0
  110. data/test/source/_posts/es/2008-11-21-nested.textile +8 -0
  111. data/test/source/about.html +6 -0
  112. data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
  113. data/test/source/contacts.html +5 -0
  114. data/test/source/contacts/bar.html +5 -0
  115. data/test/source/contacts/index.html +5 -0
  116. data/test/source/css/screen.css +76 -0
  117. data/test/source/deal.with.dots.html +7 -0
  118. data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
  119. data/test/source/index.html +22 -0
  120. data/test/source/sitemap.xml +32 -0
  121. data/test/source/symlink-test/symlinked-file +22 -0
  122. data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
  123. data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
  124. data/test/suite.rb +11 -0
  125. data/test/test_command.rb +39 -0
  126. data/test/test_configuration.rb +137 -0
  127. data/test/test_convertible.rb +51 -0
  128. data/test/test_core_ext.rb +88 -0
  129. data/test/test_filters.rb +102 -0
  130. data/test/test_generated_site.rb +83 -0
  131. data/test/test_json_driver.rb +63 -0
  132. data/test/test_kramdown.rb +35 -0
  133. data/test/test_new_command.rb +104 -0
  134. data/test/test_page.rb +193 -0
  135. data/test/test_pager.rb +115 -0
  136. data/test/test_post.rb +573 -0
  137. data/test/test_rdiscount.rb +22 -0
  138. data/test/test_redcarpet.rb +61 -0
  139. data/test/test_redcloth.rb +86 -0
  140. data/test/test_site.rb +374 -0
  141. data/test/test_tags.rb +310 -0
  142. data/test/test_yaml_driver.rb +35 -0
  143. metadata +554 -0
@@ -0,0 +1,68 @@
1
+ Contribute
2
+ ==========
3
+
4
+ So you've got an awesome idea to throw into Jekyll. Great! Please keep the
5
+ following in mind:
6
+
7
+ * **Contributions will not be accepted without tests.**
8
+ * If you're creating a small fix or patch to an existing feature, just a simple
9
+ test will do. Please stay in the confines of the current test suite and use
10
+ [Shoulda](http://github.com/thoughtbot/shoulda/tree/master) and
11
+ [RR](http://github.com/btakita/rr/tree/master).
12
+ * If it's a brand new feature, make sure to create a new
13
+ [Cucumber](https://github.com/cucumber/cucumber/) feature and reuse steps
14
+ where appropriate. Also, whipping up some documentation in your fork's wiki
15
+ would be appreciated, and once merged it will be transferred over to the main
16
+ wiki.
17
+ * If your contribution changes any Jekyll behavior, make sure to update the
18
+ documentation. It lives in `site/_posts`. If the docs are missing information,
19
+ please feel free to add it in. Great docs make a great project!
20
+ * Please follow the [GitHub Ruby Styleguide](https://github.com/styleguide/ruby)
21
+ when modifying Ruby code.
22
+
23
+ Test Dependencies
24
+ -----------------
25
+
26
+ To run the test suite and build the gem you'll need to install Jekyll's
27
+ dependencies. Jekyll uses Bundler, so a quick run of the bundle command and
28
+ you're all set!
29
+
30
+ $ bundle
31
+
32
+ Before you start, run the tests and make sure that they pass (to confirm your
33
+ environment is configured properly):
34
+
35
+ $ rake test
36
+ $ rake features
37
+
38
+ Workflow
39
+ --------
40
+
41
+ Here's the most direct way to get your work merged into the project:
42
+
43
+ * Fork the project.
44
+ * Clone down your fork ( `git clone git@github.com:<username>/jekyll.git` ).
45
+ * Create a topic branch to contain your change ( `git checkout -b my_awesome_feature` ).
46
+ * Hack away, add tests. Not necessarily in that order.
47
+ * Make sure everything still passes by running `rake`.
48
+ * If necessary, rebase your commits into logical chunks, without errors.
49
+ * Push the branch up ( `git push origin my_awesome_feature` ).
50
+ * Create a pull request against mojombo/jekyll and describe what your change
51
+ does and the why you think it should be merged.
52
+
53
+ Gotchas
54
+ -------
55
+
56
+ * If you want to bump the gem version, please put that in a separate commit.
57
+ This way, the maintainers can control when the gem gets released.
58
+ * Try to keep your patch(es) based from the latest commit on mojombo/jekyll.
59
+ The easier it is to apply your work, the less work the maintainers have to do,
60
+ which is always a good thing.
61
+ * Please don't tag your GitHub issue with [fix], [feature], etc. The maintainers
62
+ actively read the issues and will label it once they come across it.
63
+
64
+ Finally...
65
+ ----------
66
+
67
+ Thanks! Hacking on Jekyll should be fun. If you find any of this hard to figure
68
+ out, let us know so we can improve our process or documentation!
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2008 Tom Preston-Werner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,88 @@
1
+ ## Monad
2
+
3
+ Monad is a simple, blog aware, static site generator based on and 100% compatible with [Jekyll](https://github.com/mojombo/jekyll).
4
+
5
+ The main feature it adds is as follows:
6
+
7
+ - Support data sources
8
+ - Support virtual posts from external sources(TBD)
9
+
10
+ ## Data Sources
11
+
12
+ Data Source enables you to load data from external sources, such as web, file system,
13
+ databases and then use them inside views.
14
+
15
+ Jekyll supports two built-in data sources:
16
+
17
+ - `YAML` from local file system
18
+ - `JSON` from web
19
+
20
+ And it's easy to roll your own data source driver.
21
+
22
+ ### JSON
23
+
24
+ In ordre to use json from web in your site, set following in `_config.yml` file:
25
+
26
+ ``` yaml
27
+ data_sources:
28
+ - name: albums # will be used as site.albums to access data, no spaces allowed
29
+ type: json
30
+ url: http://www.example.com/albums.json # must be http or https
31
+ ```
32
+
33
+ Then, inside html you can access the data as following:
34
+
35
+ {% for album in site.albums %}
36
+ ...
37
+ {% endfor %}
38
+
39
+ ### YAML
40
+
41
+ To define a yaml data source, set following in `_config.yml` file:
42
+
43
+ ``` yaml
44
+ data_sources:
45
+ - name: products # will be used as site.products to access data, no spaces allowed
46
+ type: yaml
47
+ path: _data/products.yml # must be on local file system
48
+ ```
49
+
50
+ Then, inside html you can access the data as following:
51
+
52
+ {% for product in site.products %}
53
+ ...
54
+ {% endfor %}
55
+
56
+ ### Custom drivers
57
+
58
+ The skeleton of your driver should be as follows:
59
+
60
+ ``` ruby
61
+ module Monad
62
+ module Drivers
63
+ class XxxDriver
64
+ # source options are passed in as an Hash
65
+ def initialize(options)
66
+ end
67
+
68
+ # return the loaded data as Array or Hash or a nested structure of Array and Hash
69
+ def load
70
+ end
71
+ end
72
+ end
73
+ end
74
+ ```
75
+
76
+ After you've implemented the code, put the source file inside `_plugins` directory.
77
+
78
+ Then in `_config.yml`, you can use the driver as follows:
79
+
80
+ ``` yaml
81
+ data_sources:
82
+ - name: students
83
+ type: xxx
84
+ ```
85
+
86
+ If the type is `xxx`, Jekyll assumes the corresponding driver is `Monad::Drivers::XxxDriver`. If the type is `xxx_yyy`, the driver should be `Monad::Drivers::XxxYyyDriver`, and so on.
87
+
88
+ Beside the obligatory `name` and `type` options, you can define any more options to be used inside the driver.
@@ -0,0 +1,136 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rdoc'
4
+ require 'date'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w[lib]))
7
+
8
+ #############################################################################
9
+ #
10
+ # Helper functions
11
+ #
12
+ #############################################################################
13
+
14
+ def name
15
+ @name ||= Dir['*.gemspec'].first.split('.').first
16
+ end
17
+
18
+ def version
19
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
20
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
21
+ end
22
+
23
+ def date
24
+ Date.today.to_s
25
+ end
26
+
27
+ def rubyforge_project
28
+ name
29
+ end
30
+
31
+ def gemspec_file
32
+ "#{name}.gemspec"
33
+ end
34
+
35
+ def gem_file
36
+ "#{name}-#{version}.gem"
37
+ end
38
+
39
+ def replace_header(head, header_name)
40
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
41
+ end
42
+
43
+ #############################################################################
44
+ #
45
+ # Standard tasks
46
+ #
47
+ #############################################################################
48
+
49
+ task :default => [:test, :features]
50
+
51
+ require 'rake/testtask'
52
+ Rake::TestTask.new(:test) do |test|
53
+ test.libs << 'lib' << 'test'
54
+ test.pattern = 'test/**/test_*.rb'
55
+ test.verbose = true
56
+ end
57
+
58
+ require 'rdoc/task'
59
+ Rake::RDocTask.new do |rdoc|
60
+ rdoc.rdoc_dir = 'rdoc'
61
+ rdoc.title = "#{name} #{version}"
62
+ rdoc.rdoc_files.include('README*')
63
+ rdoc.rdoc_files.include('lib/**/*.rb')
64
+ end
65
+
66
+ begin
67
+ require 'cucumber/rake/task'
68
+ Cucumber::Rake::Task.new(:features) do |t|
69
+ t.profile = "travis"
70
+ end
71
+ Cucumber::Rake::Task.new(:"features:html", "Run Cucumber features and produce HTML output") do |t|
72
+ t.profile = "html_report"
73
+ end
74
+ rescue LoadError
75
+ desc 'Cucumber rake task not available'
76
+ task :features do
77
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
78
+ end
79
+ end
80
+
81
+ desc "Open an irb session preloaded with this library"
82
+ task :console do
83
+ sh "irb -rubygems -r ./lib/#{name}.rb"
84
+ end
85
+
86
+ #############################################################################
87
+ #
88
+ # Packaging tasks
89
+ #
90
+ #############################################################################
91
+
92
+ task :release => :build do
93
+ unless `git branch` =~ /^\* master$/
94
+ puts "You must be on the master branch to release!"
95
+ exit!
96
+ end
97
+ sh "git commit --allow-empty -m 'Release #{version}'"
98
+ sh "git tag v#{version}"
99
+ sh "git push origin master"
100
+ sh "git push origin v#{version}"
101
+ sh "gem push pkg/#{name}-#{version}.gem"
102
+ end
103
+
104
+ task :build => :gemspec do
105
+ sh "mkdir -p pkg"
106
+ sh "gem build #{gemspec_file}"
107
+ sh "mv #{gem_file} pkg"
108
+ end
109
+
110
+ task :gemspec do
111
+ # read spec file and split out manifest section
112
+ spec = File.read(gemspec_file)
113
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
114
+
115
+ # replace name version and date
116
+ replace_header(head, :name)
117
+ replace_header(head, :version)
118
+ replace_header(head, :date)
119
+ #comment this out if your rubyforge_project has a different name
120
+ replace_header(head, :rubyforge_project)
121
+
122
+ # determine file list from git ls-files
123
+ files = `git ls-files`.
124
+ split("\n").
125
+ sort.
126
+ reject { |file| file =~ /^\./ }.
127
+ reject { |file| file =~ /^(rdoc|pkg|coverage)/ }.
128
+ map { |file| " #{file}" }.
129
+ join("\n")
130
+
131
+ # piece file back together and write
132
+ manifest = " s.files = %w[\n#{files}\n ]\n"
133
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
134
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
135
+ puts "Updated #{gemspec_file}"
136
+ end
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env ruby
2
+ STDOUT.sync = true
3
+
4
+ $:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
5
+
6
+ require 'commander/import'
7
+ require 'monad'
8
+
9
+ Monad::Deprecator.process(ARGV)
10
+
11
+ program :name, 'monad'
12
+ program :version, Monad::VERSION
13
+ program :description, 'Monad is a blog-aware, static site generator in Ruby based on jekyll'
14
+
15
+ default_command :help
16
+
17
+ global_option '-s', '--source [DIR]', 'Source directory (defaults to ./)'
18
+ global_option '-d', '--destination [DIR]', 'Destination directory (defaults to ./_site)'
19
+ global_option '--safe', 'Safe mode (defaults to false)'
20
+ global_option '--plugins PLUGINS_DIR1[,PLUGINS_DIR2[,...]]', Array, 'Plugins directory (defaults to ./_plugins)'
21
+ global_option '--layouts', 'Layouts directory (defaults to ./_layouts)'
22
+
23
+ # Option names don't always directly match the configuration value we'd like.
24
+ # This method will rename options to match what Monad configuration expects.
25
+ #
26
+ # options - The Hash of options from Commander.
27
+ #
28
+ # Returns the normalized Hash.
29
+ def normalize_options(options)
30
+ if drafts_state = options.delete(:drafts)
31
+ options[:show_drafts] = drafts_state
32
+ end
33
+ options
34
+ end
35
+
36
+ command :new do |c|
37
+ c.syntax = 'monad new PATH'
38
+ c.description = 'Creates a new Monad site scaffold in PATH'
39
+
40
+ c.action do |args, options|
41
+ Monad::Commands::New.process(args)
42
+ end
43
+ end
44
+
45
+ command :build do |c|
46
+ c.syntax = 'monad build [options]'
47
+ c.description = 'Build your site'
48
+
49
+ c.option '--config CONFIG_FILE[,CONFIG_FILE2,...]', Array, 'Custom configuration file'
50
+ c.option '--future', 'Publishes posts with a future date'
51
+ c.option '--limit_posts MAX_POSTS', Integer, 'Limits the number of posts to parse and publish'
52
+ c.option '-w', '--watch', 'Watch for changes and rebuild'
53
+ c.option '--lsi', 'Use LSI for improved related posts'
54
+ c.option '--drafts', 'Render posts in the _drafts folder'
55
+
56
+ c.action do |args, options|
57
+ options = normalize_options(options.__hash__)
58
+ options = Monad.configuration(options)
59
+ Monad::Commands::Build.process(options)
60
+ end
61
+ end
62
+
63
+ command :serve do |c|
64
+ c.syntax = 'monad serve [options]'
65
+ c.description = 'Serve your site locally'
66
+
67
+ c.option '--config CONFIG_FILE[,CONFIG_FILE2,...]', Array, 'Custom configuration file'
68
+ c.option '--future', 'Publishes posts with a future date'
69
+ c.option '--limit_posts MAX_POSTS', Integer, 'Limits the number of posts to parse and publish'
70
+ c.option '-w', '--watch', 'Watch for changes and rebuild'
71
+ c.option '--lsi', 'Use LSI for improved related posts'
72
+ c.option '--drafts', 'Render posts in the _drafts folder'
73
+
74
+ c.option '-p', '--port [PORT]', 'Port to listen on'
75
+ c.option '-h', '--host [HOST]', 'Host to bind to'
76
+ c.option '-b', '--baseurl [URL]', 'Base URL'
77
+
78
+ c.action do |args, options|
79
+ options.default :serving => true
80
+
81
+ options = normalize_options(options.__hash__)
82
+ options = Monad.configuration(options)
83
+ Monad::Commands::Build.process(options)
84
+ Monad::Commands::Serve.process(options)
85
+ end
86
+ end
87
+ alias_command :server, :serve
88
+
89
+ command :doctor do |c|
90
+ c.syntax = 'monad doctor'
91
+ c.description = 'Search site and print specific deprecation warnings'
92
+
93
+ c.option '--config CONFIG_FILE[,CONFIG_FILE2,...]', Array, 'Custom configuration file'
94
+
95
+ c.action do |args, options|
96
+ options = normalize_options(options.__hash__)
97
+ options = Monad.configuration(options)
98
+ Monad::Commands::Doctor.process(options)
99
+ end
100
+ end
101
+ alias_command :hyde, :doctor
102
+
@@ -0,0 +1,3 @@
1
+ default: --format pretty
2
+ travis: --format progress
3
+ html_report: --format progress --format html --out=features_report.html
@@ -0,0 +1,112 @@
1
+ Feature: Create sites
2
+ As a hacker who likes to blog
3
+ I want to be able to make a static site
4
+ In order to share my awesome ideas with the interwebs
5
+
6
+ Scenario: Basic site
7
+ Given I have an "index.html" file that contains "Basic Site"
8
+ When I run monad
9
+ Then the _site directory should exist
10
+ And I should see "Basic Site" in "_site/index.html"
11
+
12
+ Scenario: Basic site with a post
13
+ Given I have a _posts directory
14
+ And I have the following post:
15
+ | title | date | content |
16
+ | Hackers | 3/27/2009 | My First Exploit |
17
+ When I run monad
18
+ Then the _site directory should exist
19
+ And I should see "My First Exploit" in "_site/2009/03/27/hackers.html"
20
+
21
+ Scenario: Basic site with layout and a page
22
+ Given I have a _layouts directory
23
+ And I have an "index.html" page with layout "default" that contains "Basic Site with Layout"
24
+ And I have a default layout that contains "Page Layout: {{ content }}"
25
+ When I run monad
26
+ Then the _site directory should exist
27
+ And I should see "Page Layout: Basic Site with Layout" in "_site/index.html"
28
+
29
+ Scenario: Basic site with layout and a post
30
+ Given I have a _layouts directory
31
+ And I have a _posts directory
32
+ And I have the following posts:
33
+ | title | date | layout | content |
34
+ | Wargames | 3/27/2009 | default | The only winning move is not to play. |
35
+ And I have a default layout that contains "Post Layout: {{ content }}"
36
+ When I run monad
37
+ Then the _site directory should exist
38
+ And I should see "Post Layout: <p>The only winning move is not to play.</p>" in "_site/2009/03/27/wargames.html"
39
+
40
+ Scenario: Basic site with layouts, pages, posts and files
41
+ Given I have a _layouts directory
42
+ And I have a page layout that contains "Page {{ page.title }}: {{ content }}"
43
+ And I have a post layout that contains "Post {{ page.title }}: {{ content }}"
44
+ And I have an "index.html" page with layout "page" that contains "Site contains {{ site.pages.size }} pages and {{ site.posts.size }} posts"
45
+ And I have a blog directory
46
+ And I have a "blog/index.html" page with layout "page" that contains "blog category index page"
47
+ And I have an "about.html" file that contains "No replacement {{ site.posts.size }}"
48
+ And I have an "another_file" file that contains ""
49
+ And I have a _posts directory
50
+ And I have the following posts:
51
+ | title | date | layout | content |
52
+ | entry1 | 3/27/2009 | post | content for entry1. |
53
+ | entry2 | 4/27/2009 | post | content for entry2. |
54
+ And I have a category/_posts directory
55
+ And I have the following posts in "category":
56
+ | title | date | layout | content |
57
+ | entry3 | 5/27/2009 | post | content for entry3. |
58
+ | entry4 | 6/27/2009 | post | content for entry4. |
59
+ When I run monad
60
+ Then the _site directory should exist
61
+ And I should see "Page : Site contains 2 pages and 4 posts" in "_site/index.html"
62
+ And I should see "No replacement \{\{ site.posts.size \}\}" in "_site/about.html"
63
+ And I should see "" in "_site/another_file"
64
+ And I should see "Page : blog category index page" in "_site/blog/index.html"
65
+ And I should see "Post entry1: <p>content for entry1.</p>" in "_site/2009/03/27/entry1.html"
66
+ And I should see "Post entry2: <p>content for entry2.</p>" in "_site/2009/04/27/entry2.html"
67
+ And I should see "Post entry3: <p>content for entry3.</p>" in "_site/category/2009/05/27/entry3.html"
68
+ And I should see "Post entry4: <p>content for entry4.</p>" in "_site/category/2009/06/27/entry4.html"
69
+
70
+ Scenario: Basic site with include tag
71
+ Given I have a _includes directory
72
+ And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
73
+ And I have an "_includes/about.textile" file that contains "Generated by Monad"
74
+ When I run monad
75
+ Then the _site directory should exist
76
+ And I should see "Basic Site with include tag: Generated by Monad" in "_site/index.html"
77
+
78
+ Scenario: Basic site with subdir include tag
79
+ Given I have a _includes directory
80
+ And I have an "_includes/about.textile" file that contains "Generated by Monad"
81
+ And I have an info directory
82
+ And I have an "info/index.html" page that contains "Basic Site with subdir include tag: {% include about.textile %}"
83
+ When I run monad
84
+ Then the _site directory should exist
85
+ And I should see "Basic Site with subdir include tag: Generated by Monad" in "_site/info/index.html"
86
+
87
+ Scenario: Basic site with nested include tag
88
+ Given I have a _includes directory
89
+ And I have an "_includes/about.textile" file that contains "Generated by {% include monad.textile %}"
90
+ And I have an "_includes/monad.textile" file that contains "Monad"
91
+ And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
92
+ When I run monad
93
+ Then the _site directory should exist
94
+ And I should see "Basic Site with include tag: Generated by Monad" in "_site/index.html"
95
+
96
+ Scenario: Basic site with internal post linking
97
+ Given I have an "index.html" page that contains "URL: {% post_url 2020-01-31-entry2 %}"
98
+ And I have a configuration file with "permalink" set to "pretty"
99
+ And I have a _posts directory
100
+ And I have the following posts:
101
+ | title | date | layout | content |
102
+ | entry1 | 12/31/2007 | post | content for entry1. |
103
+ | entry2 | 01/31/2020 | post | content for entry2. |
104
+ When I run monad
105
+ Then the _site directory should exist
106
+ And I should see "URL: /2020/01/31/entry2/" in "_site/index.html"
107
+
108
+ Scenario: Basic site with whitelisted dotfile
109
+ Given I have an ".htaccess" file that contains "SomeDirective"
110
+ When I run monad
111
+ Then the _site directory should exist
112
+ And I should see "SomeDirective" in "_site/.htaccess"