ruhoh 2.5 → 2.6

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 (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
@@ -1,67 +0,0 @@
1
- module Ruhoh::Base
2
-
3
- module Compilable
4
- def self.included(klass)
5
- __send__(:attr_reader, :collection)
6
- end
7
-
8
- def initialize(collection)
9
- @ruhoh = collection.ruhoh
10
- @collection = collection
11
- end
12
-
13
- def setup_compilable
14
- return false unless collection_exists?
15
-
16
- compile_collection_path
17
- end
18
-
19
- def compile_collection_path
20
- FileUtils.mkdir_p(@collection.compiled_path)
21
- end
22
-
23
- def collection_exists?
24
- collection = @collection
25
- unless @collection.paths?
26
- Ruhoh::Friend.say { yellow "#{ collection.resource_name.capitalize }: directory not found - skipping." }
27
- return false
28
- end
29
- Ruhoh::Friend.say { cyan "#{ collection.resource_name.capitalize }: (copying valid files)" }
30
- true
31
- end
32
- end
33
-
34
- module CompilableAsset
35
- include Compilable
36
-
37
- # A basic compiler task which copies each valid collection resource file to the compiled folder.
38
- # This is different from the static compiler in that it supports fingerprinting.
39
- # Valid files are identified by their pointers.
40
- # Invalid files are files that are excluded from the resource's configuration settings.
41
- # The collection's url_endpoint is used to determine the final compiled path.
42
- #
43
- # @returns Nothing.
44
- def run
45
- return unless setup_compilable
46
-
47
- manifest = {}
48
- @collection.files.values.each do |pointer|
49
- digest = Digest::MD5.file(pointer['realpath']).hexdigest
50
- digest_file = pointer['id'].sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
51
- manifest[pointer['id']] = digest_file
52
-
53
- compiled_file = File.join(@collection.compiled_path, digest_file)
54
- FileUtils.mkdir_p File.dirname(compiled_file)
55
- FileUtils.cp_r pointer['realpath'], compiled_file
56
- Ruhoh::Friend.say { green " > #{pointer['id']}" }
57
- end
58
-
59
- # Update the paths to the digest format:
60
- @collection.load_collection_view._cache.merge!(manifest)
61
- end
62
- end
63
-
64
- class Compiler
65
- include Ruhoh::Base::Compilable
66
- end
67
- end
@@ -1,161 +0,0 @@
1
- module Ruhoh::Base
2
- module Modelable
3
- include Observable
4
-
5
- def self.included(klass)
6
- klass.__send__(:attr_reader, :pointer, :ruhoh)
7
- end
8
-
9
- def initialize(ruhoh, pointer)
10
- raise "Cannot instantiate a model with a nil pointer" unless pointer
11
- @ruhoh = ruhoh
12
- @pointer = pointer
13
- end
14
-
15
- # @returns[Hash Object] Top page metadata
16
- def data
17
- return @data if @data
18
- process
19
- @data || {}
20
- end
21
-
22
- # @returns[String] Raw (unconverted) page content
23
- def content
24
- return @content if @content
25
- process
26
- @content || ''
27
- end
28
-
29
- def collection
30
- @ruhoh.collection(@pointer['resource'])
31
- end
32
-
33
- # Override this to process custom data
34
- def process
35
- changed
36
- notify_observers(@pointer)
37
- @pointer
38
- end
39
-
40
- def try(method)
41
- return __send__(method) if respond_to?(method)
42
- return data[method.to_s] if data.key?(method.to_s)
43
- false
44
- end
45
- end
46
-
47
- module PageLike
48
- include Modelable
49
-
50
- DateMatcher = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
51
- Matcher = /^(.+\/)*(.*)(\.[^.]+)$/
52
-
53
- # Process this file. See #parse_page_file
54
- # @return[Hash] the processed data from the file.
55
- # ex:
56
- # { "content" => "..", "data" => { "key" => "value" } }
57
- def process
58
- return {} unless file?
59
-
60
- parsed_page = parse_page_file
61
- data = parsed_page['data']
62
-
63
- filename_data = parse_page_filename(@pointer['id'])
64
-
65
- data['pointer'] = @pointer
66
- data['id'] = @pointer['id']
67
-
68
- data['title'] = data['title'] || filename_data['title']
69
- data['date'] ||= filename_data['date']
70
-
71
- # Parse and store date as an object
72
- begin
73
- data['date'] = Time.parse(data['date']) unless data['date'].nil? || data['date'].is_a?(Time)
74
- rescue
75
- Ruhoh.log.error(
76
- "ArgumentError: The date '#{data['date']}' specified in '#{@pointer['id']}' is unparsable."
77
- )
78
- data['date'] = nil
79
- end
80
- data['url'] = url(data)
81
- data['layout'] = collection.config['layout'] if data['layout'].nil?
82
-
83
- parsed_page['data'] = data
84
-
85
- changed
86
- notify_observers(parsed_page)
87
- data
88
- end
89
-
90
- protected
91
-
92
- # Is the resource backed by a physical file in the filesystem?
93
- # For example the pagination system uses a page-stub
94
- # that has no reference to an actual file.
95
- # @return[Boolean]
96
- def file?
97
- !!@pointer['realpath']
98
- end
99
-
100
- # See Ruhoh::Parse.page_file
101
- # @returns[Hash Object] processed top meta-data, raw (unconverted) content body
102
- def parse_page_file
103
- raise "File not found: #{@pointer['realpath']}" unless File.exist?(@pointer['realpath'])
104
- result = Ruhoh::Parse.page_file(@pointer['realpath'])
105
-
106
- # variable cache
107
- @data = result["data"]
108
- @content = result['content']
109
-
110
- result
111
- end
112
-
113
- def parse_page_filename(filename)
114
- data = *filename.match(DateMatcher)
115
- data = *filename.match(Matcher) if data.empty?
116
- return {} if data.empty?
117
-
118
- if filename =~ DateMatcher
119
- {
120
- "path" => data[1],
121
- "date" => data[2],
122
- "slug" => data[3],
123
- "title" => self.to_title(data[3]),
124
- "extension" => data[4]
125
- }
126
- else
127
- {
128
- "path" => data[1],
129
- "slug" => data[2],
130
- "title" => to_title(data[2]),
131
- "extension" => data[3]
132
- }
133
- end
134
- end
135
-
136
- # my-post-title ===> My Post Title
137
- def to_title(file_slug)
138
- if file_slug == 'index' && !@pointer['id'].index('/').nil?
139
- file_slug = @pointer['id'].split('/')[-2]
140
- end
141
-
142
- Ruhoh::StringFormat.titleize(file_slug)
143
- end
144
-
145
- def url(page_data)
146
- page_data['permalink_ext'] ||= collection.config['permalink_ext']
147
-
148
- format = page_data['permalink'] ||
149
- collection.config['permalink'] ||
150
- "/:path/:filename"
151
-
152
- slug = Ruhoh::UrlSlug.new(page_data: page_data, format: format)
153
-
154
- @ruhoh.to_url(slug.generate)
155
- end
156
- end
157
-
158
- class Model
159
- include Modelable
160
- end
161
- end
@@ -1,129 +0,0 @@
1
- require 'ruhoh/summarizer'
2
-
3
- module Ruhoh::Base
4
- module ModelViewable
5
- def initialize(model)
6
- super(model)
7
- @model = model
8
- @ruhoh = model.ruhoh
9
-
10
- # Define direct access to the data Hash object
11
- # but don't overwrite methods if already defined.
12
- data.keys.each do |method|
13
- (class << self; self; end).class_eval do
14
- next if method_defined?(method)
15
- define_method method do |*args, &block|
16
- data[method]
17
- end
18
- end
19
- end
20
- end
21
-
22
- def <=>(other)
23
- id <=> other.id
24
- end
25
-
26
- def [](attribute)
27
- __send__(attribute)
28
- end
29
-
30
- def []=(key, value)
31
- __send__("#{key}=", value)
32
- end
33
- end
34
-
35
- module PageViewable
36
- include ModelViewable
37
-
38
- # Default order by alphabetical title name.
39
- def <=>(other)
40
- sort = @model.collection.config["sort"] || []
41
- attribute = sort[0] || "title"
42
- direction = sort[1] || "asc"
43
-
44
- this_data = __send__(attribute)
45
- other_data = other.__send__(attribute)
46
- if attribute == "date"
47
- if this_data.nil? || other_data.nil?
48
- Ruhoh.log.error(
49
- "ArgumentError:" +
50
- " The '#{ @model.collection.resource_name }' collection is configured to sort based on 'date'" +
51
- " but '#{ @model.pointer['id'] }' has no parseable date in its metadata." +
52
- " Add date: 'YYYY-MM-DD' to its YAML metadata."
53
- )
54
- end
55
- direction = sort[1] || "desc" #default should be reverse
56
- end
57
-
58
- if direction == "asc"
59
- this_data <=> other_data
60
- else
61
- other_data <=> this_data
62
- end
63
- end
64
-
65
- def categories
66
- @model.collection.to_categories(data['categories'])
67
- end
68
-
69
- def tags
70
- @model.collection.to_tags(data['tags'])
71
- end
72
-
73
- # Lazy-load the page body.
74
- # Notes:
75
- # @content is not used for caching, it's used to manually
76
- # define content for a given page. Useful in the case that
77
- # you want to model a resource that does not actually
78
- # reference a file.
79
- def content
80
- return @content if @content
81
- content = @model.collection.master.render(@model.content)
82
- Ruhoh::Converter.convert(content, id)
83
- end
84
-
85
- def is_active_page
86
- id == @model.collection.master.page_data['id']
87
- end
88
-
89
- def summary
90
- model_data = @model.data
91
- collection_config = @model.collection.config
92
-
93
- line_limit = model_data['summary_lines'] ||
94
- collection_config['summary_lines']
95
- stop_at_header = model_data['summary_stop_at_header'] ||
96
- collection_config['summary_stop_at_header']
97
-
98
- Ruhoh::Summarizer.new({
99
- content: @ruhoh.master_view(@model.pointer).render_content,
100
- line_limit: line_limit,
101
- stop_at_header: stop_at_header
102
- }).generate
103
- end
104
-
105
- def next
106
- return unless id
107
- all_cache = @model.collection.all
108
- index = all_cache.index {|p| p["id"] == id}
109
- return unless index && (index-1 >= 0)
110
- _next = all_cache[index-1]
111
- return unless _next
112
- _next
113
- end
114
-
115
- def previous
116
- return unless id
117
- all_cache = @model.collection.all
118
- index = all_cache.index {|p| p["id"] == id}
119
- return unless index && (index+1 >= 0)
120
- prev = all_cache[index+1]
121
- return unless prev
122
- prev
123
- end
124
- end
125
-
126
- class ModelView < SimpleDelegator
127
- include ModelViewable
128
- end
129
- end
@@ -1,25 +0,0 @@
1
- module Ruhoh::Base
2
- module Watchable
3
- def self.included(klass)
4
- klass.__send__(:attr_accessor, :collection)
5
- end
6
-
7
- def initialize(collection)
8
- @collection = collection
9
- end
10
-
11
- def update(path)
12
- # Drop the resource namespace
13
- matcher = File::ALT_SEPARATOR ?
14
- %r{^.+(#{ File::SEPARATOR }|#{ File::ALT_SEPARATOR })} :
15
- %r{^.+#{ File::SEPARATOR }}
16
-
17
- collection.touch(path.gsub(matcher, ''))
18
- end
19
- end
20
-
21
- # Base watcher class that loads if no custom Watcher class is defined.
22
- class Watcher
23
- include Watchable
24
- end
25
- end
@@ -1,10 +0,0 @@
1
- module Ruhoh::Resources::Dash
2
- class Collection
3
- include Ruhoh::Base::Collectable
4
-
5
- def url_endpoint
6
- "/dash"
7
- end
8
-
9
- end
10
- end
@@ -1,5 +0,0 @@
1
- module Ruhoh::Resources::Dash
2
- class Model
3
- include Ruhoh::Base::PageLike
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- module Ruhoh::Resources::Dash
2
- class ModelView < SimpleDelegator
3
- include Ruhoh::Base::PageViewable
4
- end
5
- end
@@ -1,13 +0,0 @@
1
- module Ruhoh::Resources::Dash
2
- class Previewer
3
- def initialize(ruhoh)
4
- @ruhoh = ruhoh
5
- end
6
-
7
- def call(env)
8
- pointer = @ruhoh.collection("dash").find_file('index')
9
- view = @ruhoh.master_view(pointer)
10
- [200, {'Content-Type' => 'text/html'}, [view.render_full]]
11
- end
12
- end
13
- end