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
@@ -8,7 +8,7 @@ module Ruhoh::Resources::Theme
8
8
  return unless setup_compilable
9
9
 
10
10
  self.files.each do |file|
11
- original_file = File.join(@ruhoh.paths.theme, file)
11
+ original_file = File.join(@ruhoh.cascade.theme, file)
12
12
  compiled_file = File.join(@collection.compiled_path, file)
13
13
  FileUtils.mkdir_p File.dirname(compiled_file)
14
14
  FileUtils.cp_r original_file, compiled_file
@@ -19,7 +19,7 @@ module Ruhoh::Resources::Theme
19
19
  # Returns list of all files from the theme to be compiled.
20
20
  # @returns[Array] relative filepaths
21
21
  def files
22
- FileUtils.cd(@ruhoh.paths.theme) {
22
+ FileUtils.cd(@ruhoh.cascade.theme) {
23
23
  return Dir["**/*"].select { |filepath|
24
24
  is_valid_asset?(filepath)
25
25
  }
@@ -4,8 +4,8 @@ module Ruhoh::Resources::Widgets
4
4
 
5
5
  def initialize(ruhoh)
6
6
  @ruhoh = ruhoh
7
- @path = File.join(@ruhoh.paths.base, "widgets")
8
- @system_path = File.join(@ruhoh.paths.system, "widgets")
7
+ @path = File.join(@ruhoh.cascade.base, "widgets")
8
+ @system_path = File.join(@ruhoh.cascade.system, "widgets")
9
9
  end
10
10
 
11
11
  def url_endpoint
@@ -28,7 +28,7 @@ class Ruhoh
28
28
 
29
29
  def routable
30
30
  @ruhoh.collections.all.keep_if do |r|
31
- @ruhoh.collections.collection(r).include?(Ruhoh::Resources::Pages::Routable) rescue false
31
+ @ruhoh.collections.collection(r).include?(Ruhoh::Base::Routable) rescue false
32
32
  end
33
33
  end
34
34
  end
@@ -23,7 +23,7 @@ class Ruhoh
23
23
 
24
24
  # Return a summary element if specified
25
25
  summary_el = content_doc.at_css('.' + SummaryNodeClassName)
26
- return summary_el.to_html if summary_el
26
+ return summary_el.to_html(:encoding => 'UTF-8') if summary_el
27
27
 
28
28
  # Create the summary element.
29
29
  summary_doc = Nokogiri::XML::Node.new("div", Nokogiri::HTML::Document.new)
@@ -59,7 +59,7 @@ class Ruhoh
59
59
  summary_doc << node
60
60
  end
61
61
 
62
- summary_doc.to_html
62
+ summary_doc.to_html(:encoding => 'UTF-8')
63
63
  end
64
64
  end
65
65
  end
@@ -0,0 +1,13 @@
1
+ class Ruhoh::UI::Dashboard
2
+ def initialize(ruhoh)
3
+ @ruhoh = ruhoh
4
+ end
5
+
6
+ def call(env)
7
+ path = @ruhoh.cascade.find_file('dashboard')['realpath']
8
+ template = File.open(path, 'r:UTF-8').read
9
+ view = @ruhoh.master_view({"content" => template })
10
+
11
+ [200, {'Content-Type' => 'text/html'}, [ view.content ]]
12
+ end
13
+ end
@@ -25,11 +25,12 @@ TEXT
25
25
  end
26
26
 
27
27
  def show
28
- template = File.open(File.join(File.dirname(__FILE__), 'page_not_found.html'), 'r:UTF-8').read
28
+ path = @ruhoh.cascade.find_file('page_not_found')['realpath']
29
+ template = File.open(path, 'r:UTF-8').read
29
30
  body = Mustache.render(template, {
30
31
  pointer: @pointer,
31
32
  url: @request.path,
32
- filepath: File.join(File.basename(@ruhoh.base), filepath),
33
+ filepath: File.join(File.basename(@ruhoh.cascade.base), filepath),
33
34
  content: Content
34
35
  })
35
36
 
@@ -20,15 +20,33 @@ class Ruhoh
20
20
 
21
21
  # @return[String] the dynamic URL with token substitution.
22
22
  def dynamic
23
- data.inject(@format) { |result, token|
24
- result.gsub(/:#{ Regexp.escape(token.first) }/, token.last)
25
- }.gsub(/\/+/, "/")
23
+ cache = data
24
+ result = @format
25
+ .gsub(/:[^\/\.]+/) { |a| cache[$&.gsub(':', '')] }
26
+ .gsub('//', '/')
27
+ .split('/')
28
+
29
+ # this is ugly but I'm out of ideas. Help!
30
+ last = result.pop
31
+ if uses_extension?
32
+ last = last
33
+ .split('.')
34
+ .map{ |a| Ruhoh::StringFormat.clean_slug_and_escape(a) }
35
+ .join('.')
36
+ else
37
+ last = Ruhoh::StringFormat.clean_slug_and_escape(last)
38
+ end
39
+
40
+ result
41
+ .map{ |a| Ruhoh::StringFormat.clean_slug_and_escape(a) }
42
+ .join('/') + "/#{ last }"
26
43
  end
27
44
 
28
45
  def data
29
- result = uses_date? ? date_data : {}
46
+ result = @page_data
47
+ result = result.merge(date_data) if uses_date?
48
+
30
49
  result.merge({
31
- "title" => title,
32
50
  "filename" => filename,
33
51
  "path" => path,
34
52
  "relative_path" => relative_path,
@@ -55,10 +73,6 @@ class Ruhoh
55
73
  )
56
74
  end
57
75
 
58
- def title
59
- Ruhoh::StringFormat.clean_slug_and_escape(@page_data['title'])
60
- end
61
-
62
76
  def filename
63
77
  File.basename(@page_data['id'], ext)
64
78
  end
@@ -1,4 +1,4 @@
1
1
  class Ruhoh
2
- Version = VERSION = '2.5'
2
+ Version = VERSION = '2.6'
3
3
  RuhohSpec = '2.1'
4
4
  end
@@ -51,7 +51,7 @@ module Ruhoh::Views
51
51
 
52
52
  def urls
53
53
  @ruhoh.collections.url_endpoints.merge({
54
- 'base_path' => @ruhoh.base_path,
54
+ 'base_path' => @ruhoh.config.base_path,
55
55
  'production' => @ruhoh.config["production_url"],
56
56
  'production_url' => @ruhoh.config["production_url"]
57
57
  })
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module Ruhoh::Plugins
4
+ describe Initializer do
5
+ describe 'constructor' do
6
+ it 'raises an error when block is not defined' do
7
+ expect { Initializer.new 'foo' }.to raise_error ArgumentError
8
+ expect { Initializer.new('foo') { } }.to_not raise_error
9
+ end
10
+ end
11
+
12
+ describe '#run' do
13
+ it "raises an error when it's not bound" do
14
+ initializer = Initializer.new('foo') { }
15
+ expect { initializer.run }.to raise_error RuntimeError
16
+ expect { initializer.bind(self).run }.to_not raise_error
17
+ end
18
+
19
+ it 'executes the block in the bound context' do
20
+ initializer = Initializer.new('foo') do
21
+ self << 'a' if length == 1
22
+ end
23
+ obj = ['b']
24
+ expect { initializer.bind(obj).run }.to change(obj, :length).to 2
25
+ end
26
+
27
+ it 'passes given arguments to block' do
28
+ initializer = Initializer.new('foo') do |arg|
29
+ raise 'arg is absent' if arg != 'a'
30
+ end
31
+ expect { initializer.bind(self).run }.to raise_error 'arg is absent'
32
+ expect { initializer.run 'a' }.to_not raise_error
33
+ end
34
+ end
35
+
36
+ describe '#bind' do
37
+ it 'returns self' do
38
+ initializer = Initializer.new('foo') { }
39
+ initializer.bind(self).should == initializer
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Ruhoh::Plugins
4
+ describe Plugin do
5
+ describe '::initializers' do
6
+ it 'returns an array' do
7
+ Plugin.initializers.should be_a Array
8
+ end
9
+
10
+ it 'memoizes the array' do
11
+ Plugin.initializers.object_id.should == Plugin.initializers.object_id
12
+ end
13
+ end
14
+
15
+ context 'when included in a class' do
16
+ let(:instance_class) do
17
+ Class.new do
18
+ include Plugin
19
+ end
20
+ end
21
+
22
+ it 'defines the ::initializer method' do
23
+ instance_class.should respond_to :initializer
24
+ end
25
+
26
+ describe '::initializer' do
27
+ it 'appends to initializers collection' do
28
+ expect {
29
+ instance_class.initializer('foo') { }
30
+ }.to change(Plugin.initializers, :length).to 1
31
+ end
32
+
33
+ it 'appends an initializer object filled with given params' do
34
+ instance_class.initializer('foo') { }
35
+ Plugin.initializers.first.name.should == 'foo'
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path '../../lib/ruhoh', __FILE__
@@ -0,0 +1,21 @@
1
+ {
2
+ "base_path" : "/"
3
+ ,
4
+ "date_format" : "%Y-%m-%d"
5
+ ,
6
+ "compiled_path" : "compiled"
7
+ ,
8
+ "compiled" : {
9
+ "use" : "ignore"
10
+ }
11
+ ,
12
+ "_root" : {
13
+ "permalink" : "/:relative_path/:filename",
14
+ "paginator" : {
15
+ "url" : "/index/"
16
+ },
17
+ "rss" : {
18
+ "url" : "/"
19
+ }
20
+ }
21
+ }
@@ -209,4 +209,4 @@
209
209
  Tabs.init();
210
210
  </script>
211
211
  </body>
212
- </html>
212
+ </html>
@@ -5,6 +5,7 @@ module Ruhoh::SprocketsPlugin
5
5
  extend Ruhoh::Base::CompilableAsset
6
6
  def run
7
7
  env = Sprockets::Environment.new
8
+ #env.css_compressor = :sass
8
9
  env.logger = Logger.new(STDOUT)
9
10
  env.logger.level = Logger::WARN
10
11
 
@@ -9,7 +9,7 @@ short_name : jekyllbootstrap # Change This!
9
9
  /* * * DON'T EDIT BELOW THIS LINE * * */
10
10
  (function() {
11
11
  var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
12
- dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
12
+ dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
13
13
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
14
14
  })();
15
15
  </script>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruhoh
3
3
  version: !ruby/object:Gem::Version
4
- version: '2.5'
4
+ version: '2.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-22 00:00:00.000000000 Z
12
+ date: 2013-12-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -151,6 +151,7 @@ files:
151
151
  - Rakefile
152
152
  - bin/ruhoh
153
153
  - cucumber.yml
154
+ - features/_root.feature
154
155
  - features/base_path.feature
155
156
  - features/categories.feature
156
157
  - features/config.feature
@@ -165,6 +166,8 @@ files:
165
166
  - features/pagination.feature
166
167
  - features/partials.feature
167
168
  - features/permalinks.feature
169
+ - features/plugins.feature
170
+ - features/sort_order.feature
168
171
  - features/static.feature
169
172
  - features/step_defs.rb
170
173
  - features/stylesheets.feature
@@ -178,34 +181,45 @@ files:
178
181
  - features/widgets/widgets.feature
179
182
  - history.json
180
183
  - lib/ruhoh.rb
181
- - lib/ruhoh/base/collection.rb
182
- - lib/ruhoh/base/compiler.rb
183
- - lib/ruhoh/base/model.rb
184
- - lib/ruhoh/base/model_view.rb
185
- - lib/ruhoh/base/watcher.rb
184
+ - lib/ruhoh/base/collectable.rb
185
+ - lib/ruhoh/base/compilable.rb
186
+ - lib/ruhoh/base/compilable_asset.rb
187
+ - lib/ruhoh/base/model_viewable.rb
188
+ - lib/ruhoh/base/modelable.rb
189
+ - lib/ruhoh/base/page_like.rb
190
+ - lib/ruhoh/base/page_viewable.rb
191
+ - lib/ruhoh/base/routable.rb
192
+ - lib/ruhoh/base/watchable.rb
186
193
  - lib/ruhoh/cache.rb
194
+ - lib/ruhoh/cascade.rb
187
195
  - lib/ruhoh/client.rb
188
196
  - lib/ruhoh/collections.rb
197
+ - lib/ruhoh/config.rb
189
198
  - lib/ruhoh/console_methods.rb
190
199
  - lib/ruhoh/converter.rb
191
200
  - lib/ruhoh/converters/markdown.rb
192
201
  - lib/ruhoh/friend.rb
193
202
  - lib/ruhoh/logger.rb
194
203
  - lib/ruhoh/parse.rb
204
+ - lib/ruhoh/plugins/initializer.rb
205
+ - lib/ruhoh/plugins/local_plugins_plugin.rb
206
+ - lib/ruhoh/plugins/plugin.rb
195
207
  - lib/ruhoh/programs/compile.rb
196
208
  - lib/ruhoh/programs/preview.rb
197
209
  - lib/ruhoh/programs/watch.rb
198
210
  - lib/ruhoh/publish/rsync.rb
199
- - lib/ruhoh/resources/dash/collection.rb
200
- - lib/ruhoh/resources/dash/model.rb
201
- - lib/ruhoh/resources/dash/model_view.rb
202
- - lib/ruhoh/resources/dash/previewer.rb
211
+ - lib/ruhoh/resources/_base/collection.rb
212
+ - lib/ruhoh/resources/_base/compiler.rb
213
+ - lib/ruhoh/resources/_base/model.rb
214
+ - lib/ruhoh/resources/_base/model_view.rb
215
+ - lib/ruhoh/resources/_base/watcher.rb
203
216
  - lib/ruhoh/resources/data/collection.rb
204
217
  - lib/ruhoh/resources/data/collection_view.rb
205
218
  - lib/ruhoh/resources/ignore/collection.rb
206
219
  - lib/ruhoh/resources/javascripts/collection.rb
207
220
  - lib/ruhoh/resources/javascripts/collection_view.rb
208
221
  - lib/ruhoh/resources/javascripts/compiler.rb
222
+ - lib/ruhoh/resources/javascripts/model_view.rb
209
223
  - lib/ruhoh/resources/layouts/client.rb
210
224
  - lib/ruhoh/resources/layouts/model.rb
211
225
  - lib/ruhoh/resources/media/collection.rb
@@ -233,7 +247,7 @@ files:
233
247
  - lib/ruhoh/string_format.rb
234
248
  - lib/ruhoh/summarizer.rb
235
249
  - lib/ruhoh/time.rb
236
- - lib/ruhoh/ui/page_not_found.html
250
+ - lib/ruhoh/ui/dashboard.rb
237
251
  - lib/ruhoh/ui/page_not_found.rb
238
252
  - lib/ruhoh/url_slug.rb
239
253
  - lib/ruhoh/utils.rb
@@ -245,10 +259,15 @@ files:
245
259
  - lib/ruhoh/views/master_view.rb
246
260
  - lib/ruhoh/views/rmustache.rb
247
261
  - ruhoh.gemspec
262
+ - spec/lib/ruhoh/plugins/initializer_spec.rb
263
+ - spec/lib/ruhoh/plugins/plugin_spec.rb
264
+ - spec/spec_helper.rb
248
265
  - system/_scaffold.html
249
- - system/dash/index.html
266
+ - system/config.json
267
+ - system/dashboard.html
250
268
  - system/layouts/_scaffold.html
251
269
  - system/layouts/paginator.html
270
+ - system/page_not_found.html
252
271
  - system/partials/categories_list.html
253
272
  - system/partials/pages_list.html
254
273
  - system/partials/posts_collate.html
@@ -285,7 +304,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
285
304
  version: '0'
286
305
  segments:
287
306
  - 0
288
- hash: 4393455842480950745
307
+ hash: -1883264674327180773
289
308
  required_rubygems_version: !ruby/object:Gem::Requirement
290
309
  none: false
291
310
  requirements:
@@ -294,7 +313,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
294
313
  version: '0'
295
314
  segments:
296
315
  - 0
297
- hash: 4393455842480950745
316
+ hash: -1883264674327180773
298
317
  requirements: []
299
318
  rubyforge_project:
300
319
  rubygems_version: 1.8.24
@@ -1,284 +0,0 @@
1
- module Ruhoh::Base
2
-
3
- module Collectable
4
-
5
- def self.included(klass)
6
- klass.__send__(:attr_accessor, :resource_name, :master)
7
- klass.__send__(:attr_reader, :ruhoh)
8
- end
9
-
10
- def initialize(ruhoh)
11
- @ruhoh = ruhoh
12
- end
13
-
14
- # Public API for finding a resource from this collection
15
- # @param name_or_pointer [String, Hash]
16
- # Hash - File pointer
17
- # String - id (filename) with full extension, e.g: about-me.md
18
- # String - name (filename) without the extension e.g: about-me
19
- # Returns the first matched filename.
20
- # See implementation for how match is determined.
21
- # @param opts [Hash] Optional options
22
- # opts[:all] - true to search all files as some may be invalid as resources
23
- #
24
- # @return[model, nil] the model is always wrapped in its view.
25
- def find(name_or_pointer, opts={})
26
- pointer = find_file(name_or_pointer, opts)
27
- return nil unless pointer
28
-
29
- @ruhoh.cache.get(pointer['realpath']) ||
30
- @ruhoh.cache.set(pointer['realpath'], load_model_view(pointer))
31
- end
32
-
33
- # Public API
34
- # @return[Hash] dictionary of models { "id" => Model }
35
- def dictionary
36
- dict = {}
37
- files.values.each { |pointer|
38
- dict.merge!({
39
- pointer['id'] => find(pointer)
40
- })
41
- }
42
- dict
43
- end
44
-
45
- def resource_name
46
- @resource_name ||= self.class.name.split("::").pop
47
- end
48
-
49
- # Implemented via Observable module
50
- # See http://ruby-doc.org/stdlib-1.9.3/libdoc/observer/rdoc/Observable.html
51
- # Collection subscribes to its child models.
52
- # #update is called on model #process.
53
- # noop
54
- def update(model_data)
55
- end
56
-
57
- # The default glob for finding files.
58
- # Every file in all child directories.
59
- def glob
60
- "**/*"
61
- end
62
-
63
- # Default paths to the 3 levels of the cascade.
64
- def paths
65
- Array(@ruhoh.cascade.map{|h| h["path"]}).map { |path|
66
- collection_path = File.join(path, resource_name)
67
- next unless File.directory?(collection_path)
68
-
69
- collection_path
70
- }.compact
71
- end
72
-
73
- # Does this resource have any valid paths to process?
74
- # A valid path may exist on any of the cascade levels.
75
- # False means there are no directories on any cascade level.
76
- # @returns[Boolean]
77
- def paths?
78
- !paths.empty?
79
- end
80
-
81
- def config
82
- config = @ruhoh.config[resource_name] || {}
83
- unless config.is_a?(Hash)
84
- Ruhoh.log.error("'#{resource_name}' config key in config" +
85
- " is a #{config.class}; it needs to be a Hash (object).")
86
- end
87
- config
88
- end
89
-
90
- # NOOP
91
- # touch a model.
92
- # Used to perform custom regeneration logic against a model.
93
- def touch(name_or_pointer)
94
- end
95
-
96
- # @param key [String, Hash]
97
- # String - id (filename) with full extension, e.g: about-me.md
98
- # String - name (filename) without the extension e.g: about-me
99
- # Returns the first matched filename.
100
- # See implementation for how match is determined.
101
- # Hash - File pointer
102
- #
103
- # @param opts [Hash] Optional options
104
- # opts[:all] - true to search all files as some may be invalid as resources
105
- #
106
- # @return [pointer, nil]
107
- def find_file(key, opts={})
108
- return key if key.is_a?(Hash) # assume valid pointer
109
-
110
- dict = opts[:all] ? _all_files : files
111
-
112
- dict[key] || dict.values.find{ |a| key == a['id'].gsub(/.[^.]+$/, '') }
113
- end
114
-
115
- # Collect all files (as mapped by data resources) for this data endpoint.
116
- # Each resource can have 3 file references, one per each cascade level.
117
- # The file hashes are collected in order
118
- # so they will overwrite eachother if found.
119
-
120
- # @param id [String, Array] Optional.
121
- # Collect all files for a single data resource.
122
- # Can be many files due to the cascade.
123
- # @param [block] Optional.
124
- # Implement custom validation logic by passing in a block.
125
- # The block is given (id, self) as args.
126
- # Return true/false for whether the file is valid/invalid.
127
- #
128
- # @return[Hash] dictionary of pointers.
129
- def files(id=nil, &block)
130
- return @ruhoh.cache.get(files_cache_key) if @ruhoh.cache.get(files_cache_key)
131
-
132
- dict = _all_files
133
- dict.keep_if do |id, pointer|
134
- block_given? ? yield(id, self) : valid_file?(id)
135
- end
136
-
137
- @ruhoh.cache.set(files_cache_key, dict)
138
- dict
139
- end
140
-
141
- # Collect all files within this collection, valid or otherwise.
142
- # Each resource can have 3 file references, one per each cascade level.
143
- # The file hashes are collected in order and overwrite eachother if found.
144
- # This is a low-level method, see #files for the public interface.
145
- #
146
- # @return[Hash] dictionary of pointers.
147
- def _all_files
148
- dict = {}
149
- paths.each do |path|
150
- FileUtils.cd(path) {
151
- Dir[glob].each { |id|
152
- next unless File.exist?(id) && FileTest.file?(id)
153
- dict[id] = {
154
- "id" => id,
155
- "realpath" => File.realpath(id),
156
- "resource" => resource_name,
157
- }
158
- }
159
- }
160
- end
161
-
162
- dict
163
- end
164
-
165
- def valid_file?(filepath)
166
- return false if filepath.start_with?('.')
167
- return false if filepath.start_with?('_')
168
- excludes = Array(config['exclude']).map { |node| Regexp.new(node) }
169
- excludes.each { |regex| return false if filepath =~ regex }
170
- true
171
- end
172
-
173
- %w{
174
- collection_view
175
- model
176
- model_view
177
- client
178
- compiler
179
- watcher
180
- previewer
181
- }.each do |method_name|
182
- define_method(method_name) do
183
- get_module_namespace.const_get(camelize(method_name).to_sym)
184
- end
185
-
186
- define_method("#{method_name}?") do
187
- get_module_namespace.const_defined?(camelize(method_name).to_sym)
188
- end
189
- end
190
-
191
- def load_collection_view
192
- @_collection_view ||= collection_view? ?
193
- collection_view.new(self) :
194
- self
195
- end
196
-
197
- def load_model(pointer)
198
- _model = model? ?
199
- model.new(@ruhoh, pointer) :
200
- Ruhoh::Base::Model.new(@ruhoh, pointer)
201
- _model.add_observer(self)
202
- _model
203
- end
204
-
205
- def load_model_view(pointer)
206
- model_view? ?
207
- model_view.new(load_model(pointer)) :
208
- Ruhoh::Base::ModelView.new(load_model(pointer))
209
- end
210
-
211
- def load_client(opts)
212
- @_client ||= client.new(load_collection_view, opts)
213
- end
214
-
215
- def load_compiler
216
- @_compiler ||= compiler.new(load_collection_view)
217
- end
218
-
219
- def load_watcher(*args)
220
- @_watcher ||= watcher? ?
221
- watcher.new(load_collection_view) :
222
- Ruhoh::Base::Watcher.new(load_collection_view)
223
- end
224
-
225
- def load_previewer(*args)
226
- @_previewer ||= previewer.new(@ruhoh)
227
- end
228
-
229
- def files_cache_key
230
- "#{ resource_name }-files"
231
- end
232
-
233
- def scaffold
234
- pointer = find_file('_scaffold', all: true) || @ruhoh.find_file('_scaffold')
235
- return '' unless pointer
236
-
237
- File.open(pointer['realpath'], 'r:UTF-8') { |f| f.read }
238
- end
239
-
240
- def compiled_path
241
- @compiled_path ||= @ruhoh.compiled_path(@ruhoh.to_url(url_endpoint))
242
- end
243
-
244
- protected
245
-
246
- # Load the registered resource else default to Pages if not configured.
247
- # @returns[Constant] the resource's module namespace
248
- def get_module_namespace
249
- type = @ruhoh.config[resource_name]["use"] rescue nil
250
- if type
251
- if @ruhoh.collections.registered.include?(type)
252
- Ruhoh::Resources.const_get(camelize(type))
253
- elsif @ruhoh.collections.base.include?(type)
254
- Ruhoh::Base.const_get(camelize(type))
255
- else
256
- klass = camelize(type)
257
- Friend.say {
258
- red "#{resource_name} resource set to use:'#{type}' in config" +
259
- " but Ruhoh::Resources::#{klass} does not exist."
260
- }
261
- abort
262
- end
263
- else
264
- if @ruhoh.collections.registered.include?(resource_name)
265
- Ruhoh::Resources.const_get(camelize(resource_name))
266
- else
267
- Ruhoh::Resources.const_get(:Pages)
268
- end
269
- end
270
- end
271
-
272
- def camelize(name)
273
- name.to_s.split('_').map { |a| a.capitalize }.join
274
- end
275
- end
276
-
277
- # Generic base implementation of a Collection class.
278
- # All collections use this class by default
279
- # unless the Collection class is explicitly defined for the resource.
280
- class Collection
281
- include Collectable
282
- end
283
-
284
- end