ruhoh 2.5 → 2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/Gemfile +1 -1
  2. data/bin/ruhoh +10 -3
  3. data/features/_root.feature +11 -0
  4. data/features/data.feature +78 -0
  5. data/features/javascripts.feature +36 -0
  6. data/features/permalinks.feature +23 -0
  7. data/features/plugins.feature +84 -0
  8. data/features/sort_order.feature +121 -0
  9. data/features/step_defs.rb +3 -3
  10. data/features/support/helpers.rb +3 -5
  11. data/history.json +21 -0
  12. data/lib/ruhoh.rb +28 -123
  13. data/lib/ruhoh/base/collectable.rb +273 -0
  14. data/lib/ruhoh/base/compilable.rb +30 -0
  15. data/lib/ruhoh/base/compilable_asset.rb +30 -0
  16. data/lib/ruhoh/base/model_viewable.rb +30 -0
  17. data/lib/ruhoh/base/modelable.rb +44 -0
  18. data/lib/ruhoh/base/page_like.rb +111 -0
  19. data/lib/ruhoh/base/page_viewable.rb +92 -0
  20. data/lib/ruhoh/base/routable.rb +20 -0
  21. data/lib/ruhoh/base/watchable.rb +18 -0
  22. data/lib/ruhoh/cascade.rb +93 -0
  23. data/lib/ruhoh/client.rb +1 -3
  24. data/lib/ruhoh/collections.rb +2 -1
  25. data/lib/ruhoh/config.rb +67 -0
  26. data/lib/ruhoh/console_methods.rb +0 -2
  27. data/lib/ruhoh/parse.rb +7 -5
  28. data/lib/ruhoh/plugins/initializer.rb +24 -0
  29. data/lib/ruhoh/plugins/local_plugins_plugin.rb +10 -0
  30. data/lib/ruhoh/plugins/plugin.rb +27 -0
  31. data/lib/ruhoh/programs/compile.rb +2 -6
  32. data/lib/ruhoh/programs/preview.rb +5 -2
  33. data/lib/ruhoh/programs/watch.rb +4 -6
  34. data/lib/ruhoh/publish/rsync.rb +2 -2
  35. data/lib/ruhoh/resources/_base/collection.rb +6 -0
  36. data/lib/ruhoh/resources/_base/compiler.rb +3 -0
  37. data/lib/ruhoh/resources/_base/model.rb +3 -0
  38. data/lib/ruhoh/resources/_base/model_view.rb +3 -0
  39. data/lib/ruhoh/resources/_base/watcher.rb +4 -0
  40. data/lib/ruhoh/resources/data/collection.rb +30 -9
  41. data/lib/ruhoh/resources/javascripts/collection_view.rb +5 -1
  42. data/lib/ruhoh/resources/javascripts/model_view.rb +15 -0
  43. data/lib/ruhoh/resources/layouts/client.rb +1 -1
  44. data/lib/ruhoh/resources/pages/client.rb +2 -2
  45. data/lib/ruhoh/resources/pages/collection.rb +2 -21
  46. data/lib/ruhoh/resources/theme/compiler.rb +2 -2
  47. data/lib/ruhoh/resources/widgets/collection.rb +2 -2
  48. data/lib/ruhoh/routes.rb +1 -1
  49. data/lib/ruhoh/summarizer.rb +2 -2
  50. data/lib/ruhoh/ui/dashboard.rb +13 -0
  51. data/lib/ruhoh/ui/page_not_found.rb +3 -2
  52. data/lib/ruhoh/url_slug.rb +23 -9
  53. data/lib/ruhoh/version.rb +1 -1
  54. data/lib/ruhoh/views/master_view.rb +1 -1
  55. data/spec/lib/ruhoh/plugins/initializer_spec.rb +43 -0
  56. data/spec/lib/ruhoh/plugins/plugin_spec.rb +40 -0
  57. data/spec/spec_helper.rb +1 -0
  58. data/system/config.json +21 -0
  59. data/system/{dash/index.html → dashboard.html} +1 -1
  60. data/{lib/ruhoh/ui → system}/page_not_found.html +0 -0
  61. data/system/plugins/sprockets/compiler.rb +1 -0
  62. data/system/widgets/comments/disqus.html +1 -1
  63. metadata +34 -15
  64. data/lib/ruhoh/base/collection.rb +0 -284
  65. data/lib/ruhoh/base/compiler.rb +0 -67
  66. data/lib/ruhoh/base/model.rb +0 -161
  67. data/lib/ruhoh/base/model_view.rb +0 -129
  68. data/lib/ruhoh/base/watcher.rb +0 -25
  69. data/lib/ruhoh/resources/dash/collection.rb +0 -10
  70. data/lib/ruhoh/resources/dash/model.rb +0 -5
  71. data/lib/ruhoh/resources/dash/model_view.rb +0 -5
  72. data/lib/ruhoh/resources/dash/previewer.rb +0 -13
data/Gemfile CHANGED
@@ -13,5 +13,5 @@ end
13
13
  group :test do
14
14
  gem 'cucumber'
15
15
  gem 'capybara'
16
- gem "rspec-expectations"
16
+ gem 'rspec'
17
17
  end
data/bin/ruhoh CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
+ # Set up gems listed in the Gemfile.
6
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
7
+ if File.exists?(ENV['BUNDLE_GEMFILE'])
8
+ require 'bundler/setup'
9
+ Bundler.require :default
10
+ end
11
+
5
12
  require 'ruhoh'
6
13
  require 'ruhoh/version'
7
14
  require 'ruhoh/client'
@@ -13,7 +20,7 @@ options = Options.new
13
20
 
14
21
  opt_parser = OptionParser.new do |opts|
15
22
  opts.banner = 'Use `ruhoh help` for full command list.'
16
-
23
+
17
24
  opts.on("--hg", "Use mercurial (hg) instead of git for source control.") do
18
25
  options.hg = true
19
26
  end
@@ -21,13 +28,13 @@ opt_parser = OptionParser.new do |opts|
21
28
  opts.on("-v", "--[no-]verbose", "Run verbosely. For pages, shows extra title, url meta-data.") do |v|
22
29
  options.verbose = v
23
30
  end
24
-
31
+
25
32
  opts.on("--version", "Display current gem and ruhoh specification versions.") do
26
33
  puts "ruhoh " + Ruhoh::VERSION
27
34
  puts "RuhohSpec " + Ruhoh::RuhohSpec
28
35
  exit 0
29
36
  end
30
-
37
+
31
38
  end
32
39
  opt_parser.parse!
33
40
 
@@ -0,0 +1,11 @@
1
+ Feature: _root collection
2
+ As a content publisher
3
+ I want to include pages at my domain's root
4
+ so I can organize my content.
5
+
6
+ Scenario: Adding a page to _root folder
7
+ Given some files with values:
8
+ | file |
9
+ | _root/index.html |
10
+ When I compile my site
11
+ Then my compiled site should have the file "index.html"
@@ -61,3 +61,81 @@ Feature: Data
61
61
  And this file should contain the content node "city|alhambra"
62
62
  And this file should contain the content node "li|mango"
63
63
  And this file should contain the content node "li|kiwi"
64
+
65
+
66
+ Scenario: Defining a basic data structure in data.json and merging with a theme data.json
67
+ Given a config file with values:
68
+ | theme-test | { "use" : "theme" } |
69
+ And the file "data.json" with body:
70
+ """
71
+ {
72
+ "address": {
73
+ "city": "alhambra"
74
+ },
75
+ "name": "jade",
76
+ "fruits": [
77
+ "mango",
78
+ "kiwi"
79
+ ]
80
+ }
81
+ """
82
+ And the file "theme-test/data.json" with body:
83
+ """
84
+ {
85
+ "address": {
86
+ "city": "Berkeley"
87
+ },
88
+ "greeting": "Hai!"
89
+ }
90
+ """
91
+ And the file "_root/index.html" with body:
92
+ """
93
+ <name>{{ data.name }}</name>
94
+ <city>{{ data.address.city }}</city>
95
+ <greeting>{{ data.greeting }}</greeting>
96
+ <ul>
97
+ {{# data.fruits }}
98
+ <li>{{ . }}</li>
99
+ {{/ data.fruits }}
100
+ </ul>
101
+ """
102
+ When I compile my site
103
+ Then my compiled site should have the file "index.html"
104
+ And this file should contain the content node "name|jade"
105
+ And this file should contain the content node "city|Berkeley"
106
+ And this file should contain the content node "li|mango"
107
+ And this file should contain the content node "li|kiwi"
108
+ And this file should contain the content node "greeting|Hai!"
109
+
110
+ Scenario: Defining a basic data structure in custom data collection
111
+ Given a config file with values:
112
+ | meta | { "use" : "data" } |
113
+ Given the file "meta/data.json" with body:
114
+ """
115
+ {
116
+ "address": {
117
+ "city": "alhambra"
118
+ },
119
+ "name": "jade",
120
+ "fruits": [
121
+ "mango",
122
+ "kiwi"
123
+ ]
124
+ }
125
+ """
126
+ And the file "_root/index.html" with body:
127
+ """
128
+ <name>{{ meta.data.name }}</name>
129
+ <city>{{ meta.data.address.city }}</city>
130
+ <ul>
131
+ {{# meta.data.fruits }}
132
+ <li>{{ . }}</li>
133
+ {{/ meta.data.fruits }}
134
+ </ul>
135
+ """
136
+ When I compile my site
137
+ Then my compiled site should have the file "index.html"
138
+ And this file should contain the content node "name|jade"
139
+ And this file should contain the content node "city|alhambra"
140
+ And this file should contain the content node "li|mango"
141
+ And this file should contain the content node "li|kiwi"
@@ -40,3 +40,39 @@ Feature: Javascripts
40
40
  When I compile my site
41
41
  Then my compiled site should have the file "index.html"
42
42
  And this file should have the fingerprinted javascripts "base, app, custom"
43
+
44
+ Scenario: Using javascript objects to resolve url
45
+ Given some files with values:
46
+ | file | body |
47
+ | javascripts/base.js | var meep; |
48
+ | javascripts/app.js | console.log('haro world') |
49
+ | javascripts/custom.js | console.log('haro world') |
50
+ And the file "_root/index.html" with body:
51
+ """
52
+ ---
53
+ custom: base.js
54
+ ---
55
+ {{# page.custom?to_javascripts }}
56
+ <script type="text/javascript" src="{{url}}"></script>
57
+ {{/ page.custom?to_javascripts }}
58
+ """
59
+ When I compile my site
60
+ Then my compiled site should have the file "index.html"
61
+ And this file should have the fingerprinted javascripts "base"
62
+
63
+ Scenario: Using javascript object to resolve url and id
64
+ Given some files with values:
65
+ | file | body |
66
+ | javascripts/base.js | var meep; |
67
+ | javascripts/app.js | console.log('haro world') |
68
+ | javascripts/custom.js | console.log('haro world') |
69
+ And the file "_root/index.html" with body:
70
+ """
71
+ {{# javascripts.all }}
72
+ <script type="text/javascript" id="{{id}}" src="{{url}}"></script>
73
+ {{/ javascripts.all }}
74
+ """
75
+ When I compile my site
76
+ Then my compiled site should have the file "index.html"
77
+ And this file should have the fingerprinted javascripts "app, base, custom"
78
+
@@ -10,6 +10,13 @@ Feature: Page Permalinks
10
10
  When I compile my site
11
11
  Then my compiled site should have the file "essays/hello/index.html"
12
12
 
13
+ Scenario: Default Permalink format with nested file
14
+ Given some files with values:
15
+ | file | body |
16
+ | essays/one/two/hello.md | |
17
+ When I compile my site
18
+ Then my compiled site should have the file "essays/one/two/hello/index.html"
19
+
13
20
  # in-page configuration
14
21
 
15
22
  Scenario: Custom permalink format in page metadata.
@@ -54,6 +61,13 @@ Feature: Page Permalinks
54
61
  When I compile my site
55
62
  Then my compiled site should have the file "essays/2012/1/2/hello/index.html"
56
63
 
64
+ Scenario: Custom permalink format in page metadata using custom metadata attributes.
65
+ Given some files with values:
66
+ | file | permalink | title | arbitrary_name | body |
67
+ | essays/hello.md | /:path/:title/:arbitrary_name | Haro World | custom data | |
68
+ When I compile my site
69
+ Then my compiled site should have the file "essays/haro-world/custom-data/index.html"
70
+
57
71
  Scenario: Custom permalink format in page metadata using explicit html extension
58
72
  Given some files with values:
59
73
  | file | permalink |
@@ -139,3 +153,12 @@ Feature: Page Permalinks
139
153
  | essays/hello.md | 2012-01-02 | |
140
154
  When I compile my site
141
155
  Then my compiled site should have the file "essays/2012/1/2/hello/index.html"
156
+
157
+ Scenario: Custom permalink format in collection config using custom metadata
158
+ Given a config file with values:
159
+ | essays | { "permalink" : "/legacy/:custom_id/:rank" } |
160
+ And some files with values:
161
+ | file | custom_id | rank | body |
162
+ | essays/hello.md | 12345 | medium | |
163
+ When I compile my site
164
+ Then my compiled site should have the file "legacy/12345/medium/index.html"
@@ -0,0 +1,84 @@
1
+ Feature: Plugins
2
+ As a content publisher
3
+ I want to include custom plugins
4
+ so I have the freedom and power to customize my website and workflow.
5
+
6
+ Scenario: Loading a pages collection plugin from the plugins folder.
7
+ Given the file "plugins/pages_test.rb" with body:
8
+ """
9
+ module PagesTest
10
+ def test_plugin_method
11
+ "Hi this is output from the test plugin"
12
+ end
13
+ end
14
+ Ruhoh::Resources::Pages::CollectionView.send(:include, PagesTest)
15
+ """
16
+ And the file "_root/index.html" with body:
17
+ """
18
+ <output>{{ _root.test_plugin_method }}</output>
19
+ """
20
+ When I compile my site
21
+ Then my compiled site should have the file "index.html"
22
+ And this file should contain the content node "output|Hi this is output from the test plugin"
23
+
24
+ Scenario: Loading a pages model plugin from the plugins folder.
25
+ Given some files with values:
26
+ | file | date | body |
27
+ | _root/index.html | 2013-12-01 | <date>{{ page.friendly_date }}</date> |
28
+ Given the file "plugins/paged_model_view_addons.rb" with body:
29
+ """
30
+ module PagesModelViewAddons
31
+ def friendly_date
32
+ date.strftime("%B %d, %Y")
33
+ end
34
+ end
35
+ Ruhoh.model('pages').send(:include, PagesModelViewAddons)
36
+ """
37
+ When I compile my site
38
+ Then my compiled site should have the file "index.html"
39
+ And this file should contain the content node "date|December 01, 2013"
40
+
41
+ Scenario: Loading a custom converter from the plugins folder.
42
+ Given some files with values:
43
+ | file | body |
44
+ | _root/index.strip | <output>the quick brown fox jumps over the lazy dog</output> |
45
+ Given the file "plugins/strip_converter.rb" with body:
46
+ """
47
+ class Ruhoh
48
+ module Converter
49
+ module Strip
50
+ def self.extensions
51
+ ['.strip']
52
+ end
53
+ def self.convert(content)
54
+ content.gsub(/\s/, '')
55
+ end
56
+ end
57
+ end
58
+ end
59
+ """
60
+ When I compile my site
61
+ Then my compiled site should have the file "index.html"
62
+ And this file should contain the content node "output|thequickbrownfoxjumpsoverthelazydog"
63
+
64
+ Scenario: Loading a custom compiler from the plugins folder.
65
+ Given the file "plugins/test_compiler.rb" with body:
66
+ """
67
+ class Ruhoh
68
+ module Compiler
69
+ class Test
70
+ def initialize(ruhoh)
71
+ @ruhoh = ruhoh
72
+ end
73
+ def run
74
+ File.open(@ruhoh.compiled_path("test-file.txt"), 'w:UTF-8') do |p|
75
+ p.puts "Domo's World ^_^"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ """
82
+ When I compile my site
83
+ Then my compiled site should have the file "test-file.txt"
84
+ And this file should contain the content "Domo's World ^_^"
@@ -0,0 +1,121 @@
1
+ Feature: Page Sort Order
2
+ As a content publisher
3
+ I want to sort pages by a custom criteria
4
+ so my content makes intuitive sense to my audience.
5
+
6
+ Scenario: Default sort order - alpha title ascending
7
+ Given some files with values:
8
+ | file | body |
9
+ | essays/hello.md | |
10
+ | essays/zebra.md | |
11
+ | essays/apple.md | |
12
+ And the file "_root/index.md" with body:
13
+ """
14
+ <essays>
15
+ {{# essays.all }}{{ title }}-{{/ essays.all }}
16
+ </essays>
17
+ """
18
+ When I compile my site
19
+ Then my compiled site should have the file "index.html"
20
+ And this file should contain the content node "essays|Apple-Hello-Zebra-"
21
+
22
+ Scenario: Sort order alpha title descending
23
+ Given a config file with value:
24
+ """
25
+ { "essays" : {"sort" : ["title", "desc"]} }
26
+ """
27
+ And some files with values:
28
+ | file |
29
+ | essays/hello.md |
30
+ | essays/zebra.md |
31
+ | essays/apple.md |
32
+ And the file "_root/index.md" with body:
33
+ """
34
+ <essays>
35
+ {{# essays.all }}{{ title }}-{{/ essays.all }}
36
+ </essays>
37
+ """
38
+ When I compile my site
39
+ Then my compiled site should have the file "index.html"
40
+ And this file should contain the content node "essays|Zebra-Hello-Apple-"
41
+
42
+
43
+ Scenario: Sort order date descending
44
+ Given a config file with value:
45
+ """
46
+ { "essays" : { "sort" : ["date", "desc"] } }
47
+ """
48
+ And some files with values:
49
+ | file | date |
50
+ | essays/hello.md | 2013-12-01 |
51
+ | essays/zebra.md | 2013-12-10 |
52
+ | essays/apple.md | 2013-12-25 |
53
+ And the file "_root/index.md" with body:
54
+ """
55
+ <essays>
56
+ {{# essays.all }}{{ title }}-{{/ essays.all }}
57
+ </essays>
58
+ """
59
+ When I compile my site
60
+ Then my compiled site should have the file "index.html"
61
+ And this file should contain the content node "essays|Apple-Zebra-Hello-"
62
+
63
+ Scenario: Sort order date ascending
64
+ Given a config file with value:
65
+ """
66
+ { "essays" : { "sort" : ["date", "asc"] } }
67
+ """
68
+ And some files with values:
69
+ | file | date |
70
+ | essays/hello.md | 2013-12-01 |
71
+ | essays/zebra.md | 2013-12-10 |
72
+ | essays/apple.md | 2013-12-25 |
73
+ And the file "_root/index.md" with body:
74
+ """
75
+ <essays>
76
+ {{# essays.all }}{{ title }}-{{/ essays.all }}
77
+ </essays>
78
+ """
79
+ When I compile my site
80
+ Then my compiled site should have the file "index.html"
81
+ And this file should contain the content node "essays|Hello-Zebra-Apple-"
82
+
83
+ Scenario: Sort order numerically coerced custom-attribute
84
+ Given a config file with value:
85
+ """
86
+ { "essays" : { "sort" : ["position", "asc"] } }
87
+ """
88
+ And some files with values:
89
+ | file | position |
90
+ | essays/hello.md | 2 |
91
+ | essays/zebra.md | 1 |
92
+ | essays/apple.md | 3 |
93
+ And the file "_root/index.md" with body:
94
+ """
95
+ <essays>
96
+ {{# essays.all }}{{ title }}-{{/ essays.all }}
97
+ </essays>
98
+ """
99
+ When I compile my site
100
+ Then my compiled site should have the file "index.html"
101
+ And this file should contain the content node "essays|Zebra-Hello-Apple-"
102
+
103
+ Scenario: Sort order alpha coerced custom-attribute
104
+ Given a config file with value:
105
+ """
106
+ { "essays" : { "sort" : ["position", "asc"] } }
107
+ """
108
+ And some files with values:
109
+ | file | position |
110
+ | essays/hello.md | c |
111
+ | essays/zebra.md | b |
112
+ | essays/apple.md | a |
113
+ And the file "_root/index.md" with body:
114
+ """
115
+ <essays>
116
+ {{# essays.all }}{{ title }}-{{/ essays.all }}
117
+ </essays>
118
+ """
119
+ When I compile my site
120
+ Then my compiled site should have the file "index.html"
121
+ And this file should contain the content node "essays|Apple-Zebra-Hello-"
@@ -52,7 +52,7 @@ end
52
52
 
53
53
  Then(/^my compiled site (should|should NOT) have the file "(.*?)"$/) do |matcher, path|
54
54
  @filepath = path
55
- FileUtils.cd(@ruhoh.paths.compiled) {
55
+ FileUtils.cd(@ruhoh.config['compiled_path']) {
56
56
  # Done this way so the error output is more informative.
57
57
  files = Dir.glob("**/*").delete_if{ |a| File.directory?(a) }
58
58
  files.__send__(matcher, include(path))
@@ -61,7 +61,7 @@ end
61
61
 
62
62
  Then(/^my compiled site (should|should NOT) have the (?:directory|folder) "(.*?)"$/) do |matcher, path|
63
63
  @filepath = path
64
- FileUtils.cd(@ruhoh.paths.compiled) {
64
+ FileUtils.cd(@ruhoh.config['compiled_path']) {
65
65
  # Done this way so the error output is more informative.
66
66
  files = Dir.glob("**/*").delete_if{ |a| File.file?(a) }
67
67
  files.__send__(matcher, include(path))
@@ -90,7 +90,7 @@ end
90
90
  Then(/^this file (should|should NOT) have the fingerprinted (stylesheets|javascripts) "(.*)"$/) do |matcher, filetype, names|
91
91
  names = names.split(/[\s,]+/).map(&:strip)
92
92
  files = nil
93
- FileUtils.cd(File.join(@ruhoh.paths.compiled, 'assets', filetype)){
93
+ FileUtils.cd(File.join(@ruhoh.config['compiled_path'], 'assets', filetype)){
94
94
  files = Dir['*']
95
95
  }
96
96