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.
- data/Gemfile +1 -1
- data/bin/ruhoh +10 -3
- data/features/_root.feature +11 -0
- data/features/data.feature +78 -0
- data/features/javascripts.feature +36 -0
- data/features/permalinks.feature +23 -0
- data/features/plugins.feature +84 -0
- data/features/sort_order.feature +121 -0
- data/features/step_defs.rb +3 -3
- data/features/support/helpers.rb +3 -5
- data/history.json +21 -0
- data/lib/ruhoh.rb +28 -123
- data/lib/ruhoh/base/collectable.rb +273 -0
- data/lib/ruhoh/base/compilable.rb +30 -0
- data/lib/ruhoh/base/compilable_asset.rb +30 -0
- data/lib/ruhoh/base/model_viewable.rb +30 -0
- data/lib/ruhoh/base/modelable.rb +44 -0
- data/lib/ruhoh/base/page_like.rb +111 -0
- data/lib/ruhoh/base/page_viewable.rb +92 -0
- data/lib/ruhoh/base/routable.rb +20 -0
- data/lib/ruhoh/base/watchable.rb +18 -0
- data/lib/ruhoh/cascade.rb +93 -0
- data/lib/ruhoh/client.rb +1 -3
- data/lib/ruhoh/collections.rb +2 -1
- data/lib/ruhoh/config.rb +67 -0
- data/lib/ruhoh/console_methods.rb +0 -2
- data/lib/ruhoh/parse.rb +7 -5
- data/lib/ruhoh/plugins/initializer.rb +24 -0
- data/lib/ruhoh/plugins/local_plugins_plugin.rb +10 -0
- data/lib/ruhoh/plugins/plugin.rb +27 -0
- data/lib/ruhoh/programs/compile.rb +2 -6
- data/lib/ruhoh/programs/preview.rb +5 -2
- data/lib/ruhoh/programs/watch.rb +4 -6
- data/lib/ruhoh/publish/rsync.rb +2 -2
- data/lib/ruhoh/resources/_base/collection.rb +6 -0
- data/lib/ruhoh/resources/_base/compiler.rb +3 -0
- data/lib/ruhoh/resources/_base/model.rb +3 -0
- data/lib/ruhoh/resources/_base/model_view.rb +3 -0
- data/lib/ruhoh/resources/_base/watcher.rb +4 -0
- data/lib/ruhoh/resources/data/collection.rb +30 -9
- data/lib/ruhoh/resources/javascripts/collection_view.rb +5 -1
- data/lib/ruhoh/resources/javascripts/model_view.rb +15 -0
- data/lib/ruhoh/resources/layouts/client.rb +1 -1
- data/lib/ruhoh/resources/pages/client.rb +2 -2
- data/lib/ruhoh/resources/pages/collection.rb +2 -21
- data/lib/ruhoh/resources/theme/compiler.rb +2 -2
- data/lib/ruhoh/resources/widgets/collection.rb +2 -2
- data/lib/ruhoh/routes.rb +1 -1
- data/lib/ruhoh/summarizer.rb +2 -2
- data/lib/ruhoh/ui/dashboard.rb +13 -0
- data/lib/ruhoh/ui/page_not_found.rb +3 -2
- data/lib/ruhoh/url_slug.rb +23 -9
- data/lib/ruhoh/version.rb +1 -1
- data/lib/ruhoh/views/master_view.rb +1 -1
- data/spec/lib/ruhoh/plugins/initializer_spec.rb +43 -0
- data/spec/lib/ruhoh/plugins/plugin_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- data/system/config.json +21 -0
- data/system/{dash/index.html → dashboard.html} +1 -1
- data/{lib/ruhoh/ui → system}/page_not_found.html +0 -0
- data/system/plugins/sprockets/compiler.rb +1 -0
- data/system/widgets/comments/disqus.html +1 -1
- metadata +34 -15
- data/lib/ruhoh/base/collection.rb +0 -284
- data/lib/ruhoh/base/compiler.rb +0 -67
- data/lib/ruhoh/base/model.rb +0 -161
- data/lib/ruhoh/base/model_view.rb +0 -129
- data/lib/ruhoh/base/watcher.rb +0 -25
- data/lib/ruhoh/resources/dash/collection.rb +0 -10
- data/lib/ruhoh/resources/dash/model.rb +0 -5
- data/lib/ruhoh/resources/dash/model_view.rb +0 -5
- data/lib/ruhoh/resources/dash/previewer.rb +0 -13
data/lib/ruhoh/base/compiler.rb
DELETED
@@ -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
|
data/lib/ruhoh/base/model.rb
DELETED
@@ -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
|
data/lib/ruhoh/base/watcher.rb
DELETED
@@ -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,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
|