ruhoh 1.1 → 2.1
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 +3 -3
- data/README.md +3 -2
- data/Rakefile +1 -22
- data/bin/ruhoh +1 -5
- data/history.json +16 -0
- data/lib/ruhoh.rb +229 -84
- data/lib/ruhoh/base/collection.rb +280 -0
- data/lib/ruhoh/base/compiler.rb +55 -0
- data/lib/ruhoh/base/model.rb +220 -0
- data/lib/ruhoh/base/model_view.rb +152 -0
- data/lib/ruhoh/base/watcher.rb +25 -0
- data/lib/ruhoh/cache.rb +46 -0
- data/lib/ruhoh/client.rb +162 -0
- data/lib/ruhoh/collections.rb +172 -0
- data/lib/ruhoh/console_methods.rb +21 -0
- data/lib/ruhoh/{converters/converter.rb → converter.rb} +4 -1
- data/lib/ruhoh/programs/compile.rb +22 -0
- data/lib/ruhoh/programs/preview.rb +63 -0
- data/lib/ruhoh/programs/watch.rb +45 -0
- data/lib/ruhoh/resources/dash/collection.rb +10 -0
- data/lib/ruhoh/resources/dash/model.rb +5 -0
- data/lib/ruhoh/resources/dash/model_view.rb +5 -0
- data/lib/ruhoh/resources/dash/previewer.rb +13 -0
- data/lib/ruhoh/resources/data/collection.rb +9 -0
- data/lib/ruhoh/resources/data/collection_view.rb +23 -0
- data/lib/ruhoh/resources/javascripts/collection.rb +9 -0
- data/lib/ruhoh/resources/javascripts/collection_view.rb +46 -0
- data/lib/ruhoh/resources/javascripts/compiler.rb +5 -0
- data/lib/ruhoh/resources/layouts/client.rb +45 -0
- data/lib/ruhoh/resources/layouts/model.rb +16 -0
- data/lib/ruhoh/resources/media/collection.rb +9 -0
- data/lib/ruhoh/resources/media/compiler.rb +27 -0
- data/lib/ruhoh/resources/pages/client.rb +124 -0
- data/lib/ruhoh/resources/pages/collection.rb +86 -0
- data/lib/ruhoh/resources/pages/collection_view.rb +73 -0
- data/lib/ruhoh/resources/pages/compiler.rb +101 -0
- data/lib/ruhoh/resources/pages/model.rb +5 -0
- data/lib/ruhoh/resources/pages/model_view.rb +5 -0
- data/lib/ruhoh/resources/pages/previewer.rb +72 -0
- data/lib/ruhoh/resources/partials/model.rb +11 -0
- data/lib/ruhoh/resources/stylesheets/collection.rb +9 -0
- data/lib/ruhoh/resources/stylesheets/collection_view.rb +45 -0
- data/lib/ruhoh/resources/stylesheets/compiler.rb +5 -0
- data/lib/ruhoh/resources/theme/collection.rb +14 -0
- data/lib/ruhoh/resources/theme/compiler.rb +54 -0
- data/lib/ruhoh/resources/widgets/collection.rb +26 -0
- data/lib/ruhoh/resources/widgets/collection_view.rb +34 -0
- data/lib/ruhoh/resources/widgets/compiler.rb +27 -0
- data/lib/ruhoh/resources/widgets/model.rb +16 -0
- data/lib/ruhoh/routes.rb +29 -0
- data/lib/ruhoh/utils.rb +32 -49
- data/lib/ruhoh/version.rb +2 -2
- data/lib/ruhoh/views/helpers/categories.rb +38 -0
- data/lib/ruhoh/views/helpers/paginator.rb +39 -0
- data/lib/ruhoh/views/helpers/tags.rb +37 -0
- data/lib/ruhoh/views/master_view.rb +183 -0
- data/lib/ruhoh/views/rmustache.rb +24 -0
- data/ruhoh.gemspec +6 -82
- data/spec/spec_helper.rb +1 -1
- data/spec/support/shared_contexts.rb +6 -5
- data/system/{scaffolds/post.html → _scaffold.html} +1 -1
- data/system/{dash.html → dash/index.html} +37 -51
- data/system/{scaffolds/layout.html → layouts/_scaffold.html} +0 -0
- data/system/layouts/paginator.html +28 -0
- data/system/plugins/sprockets/javascripts/compiler.rb +25 -0
- data/system/plugins/sprockets/javascripts/previewer.rb +17 -0
- data/system/plugins/sprockets/stylesheets/compiler.rb +26 -0
- data/system/plugins/sprockets/stylesheets/previewer.rb +17 -0
- data/system/widgets/analytics/{layouts/getclicky.html → getclicky.html} +6 -2
- data/system/widgets/analytics/{layouts/google.html → google.html} +5 -1
- data/system/widgets/comments/{layouts/disqus.html → disqus.html} +6 -2
- data/system/widgets/comments/{layouts/facebook.html → facebook.html} +9 -2
- data/system/widgets/comments/{layouts/intensedebate.html → intensedebate.html} +5 -1
- data/system/widgets/comments/{layouts/livefyre.html → livefyre.html} +5 -1
- data/system/widgets/google_prettify/{layouts/google_prettify.html → default.html} +6 -2
- metadata +69 -66
- data/lib/ruhoh/client/client.rb +0 -306
- data/lib/ruhoh/client/console_methods.rb +0 -9
- data/lib/ruhoh/client/help.yml +0 -56
- data/lib/ruhoh/compiler.rb +0 -72
- data/lib/ruhoh/compilers/rss.rb +0 -39
- data/lib/ruhoh/compilers/theme.rb +0 -46
- data/lib/ruhoh/config.rb +0 -62
- data/lib/ruhoh/db.rb +0 -50
- data/lib/ruhoh/deployers/s3.rb +0 -71
- data/lib/ruhoh/page.rb +0 -106
- data/lib/ruhoh/parsers/javascripts.rb +0 -55
- data/lib/ruhoh/parsers/layouts.rb +0 -32
- data/lib/ruhoh/parsers/pages.rb +0 -79
- data/lib/ruhoh/parsers/partials.rb +0 -42
- data/lib/ruhoh/parsers/payload.rb +0 -49
- data/lib/ruhoh/parsers/posts.rb +0 -259
- data/lib/ruhoh/parsers/routes.rb +0 -20
- data/lib/ruhoh/parsers/scaffolds.rb +0 -35
- data/lib/ruhoh/parsers/site.rb +0 -19
- data/lib/ruhoh/parsers/stylesheets.rb +0 -63
- data/lib/ruhoh/parsers/theme_config.rb +0 -30
- data/lib/ruhoh/parsers/widgets.rb +0 -104
- data/lib/ruhoh/paths.rb +0 -83
- data/lib/ruhoh/previewer.rb +0 -48
- data/lib/ruhoh/program.rb +0 -68
- data/lib/ruhoh/templaters/asset_helpers.rb +0 -66
- data/lib/ruhoh/templaters/base_helpers.rb +0 -147
- data/lib/ruhoh/templaters/helpers.rb +0 -8
- data/lib/ruhoh/templaters/rmustache.rb +0 -70
- data/lib/ruhoh/urls.rb +0 -50
- data/lib/ruhoh/watch.rb +0 -78
- data/spec/config_spec.rb +0 -50
- data/spec/db_spec.rb +0 -91
- data/spec/page_spec.rb +0 -164
- data/spec/parsers/layouts_spec.rb +0 -41
- data/spec/parsers/pages_spec.rb +0 -120
- data/spec/parsers/posts_spec.rb +0 -309
- data/spec/parsers/routes_spec.rb +0 -39
- data/spec/parsers/site_spec.rb +0 -28
- data/spec/setup_spec.rb +0 -12
- data/system/scaffolds/draft.html +0 -9
- data/system/scaffolds/page.html +0 -4
- data/system/widgets/analytics/config.yml +0 -5
- data/system/widgets/comments/config.yml +0 -13
- data/system/widgets/google_prettify/config.yml +0 -1
@@ -0,0 +1,55 @@
|
|
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
|
+
end
|
13
|
+
|
14
|
+
module CompilableAsset
|
15
|
+
include Compilable
|
16
|
+
|
17
|
+
# A basic compiler task which copies each valid collection resource file to the compiled folder.
|
18
|
+
# Valid files are identified by their pointers.
|
19
|
+
# Invalid files are files that are excluded from the resource's configuration settings.
|
20
|
+
# The collection's url_endpoint is used to determine the final compiled path.
|
21
|
+
#
|
22
|
+
# @returns Nothing.
|
23
|
+
def run
|
24
|
+
collection = @collection
|
25
|
+
|
26
|
+
unless @collection.paths?
|
27
|
+
Ruhoh::Friend.say { yellow "#{collection.resource_name.capitalize}: directory not found - skipping." }
|
28
|
+
return
|
29
|
+
end
|
30
|
+
Ruhoh::Friend.say { cyan "#{collection.resource_name.capitalize}: (copying valid files)" }
|
31
|
+
|
32
|
+
compiled_path = Ruhoh::Utils.url_to_path(@ruhoh.to_url(@collection.url_endpoint), @ruhoh.paths.compiled)
|
33
|
+
FileUtils.mkdir_p compiled_path
|
34
|
+
|
35
|
+
manifest = {}
|
36
|
+
@collection.files.values.each do |pointer|
|
37
|
+
digest = Digest::MD5.file(pointer['realpath']).hexdigest
|
38
|
+
digest_file = pointer['id'].sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
|
39
|
+
manifest[pointer['id']] = digest_file
|
40
|
+
|
41
|
+
compiled_file = File.join(compiled_path, digest_file)
|
42
|
+
FileUtils.mkdir_p File.dirname(compiled_file)
|
43
|
+
FileUtils.cp_r pointer['realpath'], compiled_file
|
44
|
+
Ruhoh::Friend.say { green " > #{pointer['id']}" }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Update the paths to the digest format:
|
48
|
+
@collection.load_collection_view._cache.merge!(manifest)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Compiler
|
53
|
+
include Ruhoh::Base::Compilable
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,220 @@
|
|
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] if data.key?(method.to_s)
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module PageLike
|
48
|
+
include Modelable
|
49
|
+
|
50
|
+
FMregex = /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
51
|
+
DateMatcher = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
|
52
|
+
Matcher = /^(.+\/)*(.*)(\.[^.]+)$/
|
53
|
+
|
54
|
+
# Process this file. See #parse_page_file
|
55
|
+
# @return[Hash] the processed data from the file.
|
56
|
+
# ex:
|
57
|
+
# { "content" => "..", "data" => { "key" => "value" } }
|
58
|
+
def process
|
59
|
+
return {} unless file?
|
60
|
+
|
61
|
+
parsed_page = parse_page_file
|
62
|
+
data = parsed_page['data']
|
63
|
+
|
64
|
+
filename_data = parse_page_filename(@pointer['id'])
|
65
|
+
|
66
|
+
data['pointer'] = @pointer
|
67
|
+
data['id'] = @pointer['id']
|
68
|
+
|
69
|
+
data['title'] = data['title'] || filename_data['title']
|
70
|
+
data['date'] ||= filename_data['date'].to_s
|
71
|
+
data['url'] = permalink(data)
|
72
|
+
data['layout'] = collection.config['layout'] if data['layout'].nil?
|
73
|
+
|
74
|
+
parsed_page['data'] = data
|
75
|
+
|
76
|
+
changed
|
77
|
+
notify_observers(parsed_page)
|
78
|
+
data
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Is the resource backed by a physical file in the filesystem?
|
84
|
+
# For example the pagination system uses a page-stub
|
85
|
+
# that has no reference to an actual file.
|
86
|
+
# @return[Boolean]
|
87
|
+
def file?
|
88
|
+
!!@pointer['realpath']
|
89
|
+
end
|
90
|
+
|
91
|
+
# Primary method to parse the file as a page-like object.
|
92
|
+
# File API is currently defines:
|
93
|
+
# 1. Top YAML meta-data
|
94
|
+
# 2. Page Body
|
95
|
+
#
|
96
|
+
# @returns[Hash Object] processed top meta-data, raw (unconverted) content body
|
97
|
+
def parse_page_file
|
98
|
+
raise "File not found: #{@pointer['realpath']}" unless File.exist?(@pointer['realpath'])
|
99
|
+
|
100
|
+
page = File.open(@pointer['realpath'], 'r:UTF-8') {|f| f.read }
|
101
|
+
|
102
|
+
front_matter = page.match(FMregex)
|
103
|
+
data = front_matter ?
|
104
|
+
(YAML.load(front_matter[0].gsub(/---\n/, "")) || {}) :
|
105
|
+
{}
|
106
|
+
|
107
|
+
result = {
|
108
|
+
"data" => data,
|
109
|
+
"content" => page.gsub(FMregex, '')
|
110
|
+
}
|
111
|
+
|
112
|
+
# variable cache
|
113
|
+
@data = data
|
114
|
+
@content = result['content']
|
115
|
+
|
116
|
+
result
|
117
|
+
rescue Psych::SyntaxError => e
|
118
|
+
Ruhoh.log.error("Psych::SyntaxError while parsing top YAML Metadata in #{ @pointer['realpath'] }\n" +
|
119
|
+
"#{ e.message }\n" +
|
120
|
+
"Try validating the YAML metadata using http://yamllint.com"
|
121
|
+
)
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def formatted_date(date)
|
126
|
+
Time.parse(date.to_s).strftime('%Y-%m-%d') rescue false
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse_page_filename(filename)
|
130
|
+
data = *filename.match(DateMatcher)
|
131
|
+
data = *filename.match(Matcher) if data.empty?
|
132
|
+
return {} if data.empty?
|
133
|
+
|
134
|
+
if filename =~ DateMatcher
|
135
|
+
{
|
136
|
+
"path" => data[1],
|
137
|
+
"date" => data[2],
|
138
|
+
"slug" => data[3],
|
139
|
+
"title" => self.to_title(data[3]),
|
140
|
+
"extension" => data[4]
|
141
|
+
}
|
142
|
+
else
|
143
|
+
{
|
144
|
+
"path" => data[1],
|
145
|
+
"slug" => data[2],
|
146
|
+
"title" => to_title(data[2]),
|
147
|
+
"extension" => data[3]
|
148
|
+
}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# my-post-title ===> My Post Title
|
153
|
+
def to_title(file_slug)
|
154
|
+
if file_slug == 'index' && !@pointer['id'].index('/').nil?
|
155
|
+
file_slug = @pointer['id'].split('/')[-2]
|
156
|
+
end
|
157
|
+
|
158
|
+
file_slug.gsub(/[^\p{Word}+]/u, ' ').gsub(/\b\w/){$&.upcase}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Another blatently stolen method from Jekyll
|
162
|
+
# The category is only the first one if multiple categories exist.
|
163
|
+
def permalink(page_data)
|
164
|
+
format = page_data['permalink'] || collection.config['permalink']
|
165
|
+
format ||= "/:path/:filename"
|
166
|
+
|
167
|
+
url = if format.include?(':')
|
168
|
+
title = Ruhoh::Utils.to_url_slug(page_data['title'])
|
169
|
+
filename = File.basename(page_data['id'])
|
170
|
+
category = Array(page_data['categories'])[0]
|
171
|
+
category = category.split('/').map {|c| Ruhoh::Utils.to_url_slug(c) }.join('/') if category
|
172
|
+
relative_path = File.dirname(page_data['id'])
|
173
|
+
relative_path = "" if relative_path == "."
|
174
|
+
data = {
|
175
|
+
"title" => title,
|
176
|
+
"filename" => filename,
|
177
|
+
"path" => File.join(@pointer["resource"], relative_path),
|
178
|
+
"relative_path" => relative_path,
|
179
|
+
"categories" => category || '',
|
180
|
+
}
|
181
|
+
|
182
|
+
date = Date.parse(page_data['date']) rescue nil
|
183
|
+
if date
|
184
|
+
data.merge({
|
185
|
+
"year" => date.strftime("%Y"),
|
186
|
+
"month" => date.strftime("%m"),
|
187
|
+
"day" => date.strftime("%d"),
|
188
|
+
"i_day" => date.strftime("%d").to_i.to_s,
|
189
|
+
"i_month" => date.strftime("%m").to_i.to_s,
|
190
|
+
})
|
191
|
+
end
|
192
|
+
|
193
|
+
data.inject(format) { |result, token|
|
194
|
+
result.gsub(/:#{Regexp.escape token.first}/, token.last)
|
195
|
+
}.gsub(/\/+/, "/")
|
196
|
+
else
|
197
|
+
# Use the literal permalink if it is a non-tokenized string.
|
198
|
+
format.gsub(/^\//, '').split('/').map {|p| CGI::escape(p) }.join('/')
|
199
|
+
end
|
200
|
+
|
201
|
+
# Only recognize extensions registered from a 'convertable' module.
|
202
|
+
# This means 'non-convertable' extensions should pass-through.
|
203
|
+
if Ruhoh::Converter.extensions.include?(File.extname(url))
|
204
|
+
url = url.gsub(%r{#{File.extname(url)}$}, '.html')
|
205
|
+
end
|
206
|
+
|
207
|
+
unless (page_data['permalink_ext'] || collection.config['permalink_ext'])
|
208
|
+
url = url.gsub(/index.html$/, '').gsub(/\.html$/, '')
|
209
|
+
end
|
210
|
+
|
211
|
+
url = '/' if url.empty?
|
212
|
+
|
213
|
+
@ruhoh.to_url(url)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class Model
|
218
|
+
include Modelable
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Ruhoh::Base
|
2
|
+
module ModelViewable
|
3
|
+
def initialize(model)
|
4
|
+
super(model)
|
5
|
+
@model = model
|
6
|
+
@ruhoh = model.ruhoh
|
7
|
+
|
8
|
+
# TODO: THIS AUTOMATICALLY CALLS PROCESS ON THE MODEL =XXXX
|
9
|
+
# Define direct access to the data Hash object
|
10
|
+
# but don't overwrite methods if already defined.
|
11
|
+
data.keys.each do |method|
|
12
|
+
(class << self; self; end).class_eval do
|
13
|
+
next if method_defined?(method)
|
14
|
+
define_method method do |*args, &block|
|
15
|
+
data[method]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def <=>(other)
|
22
|
+
id <=> other.id
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](attribute)
|
26
|
+
__send__(attribute)
|
27
|
+
end
|
28
|
+
|
29
|
+
def []=(key, value)
|
30
|
+
__send__("#{key}=", value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module PageViewable
|
35
|
+
include ModelViewable
|
36
|
+
|
37
|
+
# Default order by alphabetical title name.
|
38
|
+
def <=>(other)
|
39
|
+
sort = @model.collection.config["sort"] || []
|
40
|
+
attribute = sort[0] || "title"
|
41
|
+
direction = sort[1] || "asc"
|
42
|
+
|
43
|
+
this_data = __send__(attribute)
|
44
|
+
other_data = other.__send__(attribute)
|
45
|
+
if attribute == "date"
|
46
|
+
begin
|
47
|
+
this_data = Date.parse(this_data)
|
48
|
+
other_data = Date.parse(other_data)
|
49
|
+
rescue ArgumentError
|
50
|
+
Ruhoh.log.error(
|
51
|
+
"ArgumentError:" +
|
52
|
+
" The '#{ @model.collection.resource_name }' collection is configured to sort based on 'date'" +
|
53
|
+
" but '#{ @model.pointer['id'] }' has no parseable date in its metadata." +
|
54
|
+
" Add date: 'YYYY-MM-DD' to its YAML metadata."
|
55
|
+
)
|
56
|
+
end
|
57
|
+
direction = sort[1] || "desc" #default should be reverse
|
58
|
+
end
|
59
|
+
|
60
|
+
if direction == "asc"
|
61
|
+
this_data <=> other_data
|
62
|
+
else
|
63
|
+
other_data <=> this_data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def categories
|
68
|
+
@model.collection.to_categories(data['categories'])
|
69
|
+
end
|
70
|
+
|
71
|
+
def tags
|
72
|
+
@model.collection.to_tags(data['tags'])
|
73
|
+
end
|
74
|
+
|
75
|
+
# Lazy-load the page body.
|
76
|
+
# Notes:
|
77
|
+
# @content is not used for caching, it's used to manually
|
78
|
+
# define content for a given page. Useful in the case that
|
79
|
+
# you want to model a resource that does not actually
|
80
|
+
# reference a file.
|
81
|
+
def content
|
82
|
+
return @content if @content
|
83
|
+
content = @model.collection.master.render(@model.content)
|
84
|
+
Ruhoh::Converter.convert(content, id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def is_active_page
|
88
|
+
id == @model.collection.master.page_data['id']
|
89
|
+
end
|
90
|
+
|
91
|
+
# Truncate the page content relative to a line_count limit.
|
92
|
+
# This is optimized for markdown files in which content is largely
|
93
|
+
# blocked into chunks and separating by blank lines.
|
94
|
+
# The line_limit truncates content based on # of content-based lines,
|
95
|
+
# so blank lines don't count toward the limit.
|
96
|
+
# Always break the content on a blank line only so result stays formatted nicely.
|
97
|
+
def summary
|
98
|
+
line_limit = @model.collection.config['summary_lines']
|
99
|
+
line_count = 0
|
100
|
+
line_breakpoint = @model.content.lines.count
|
101
|
+
|
102
|
+
content.lines.each_with_index do |line, i|
|
103
|
+
if line =~ /^\s*$/ # line with only whitespace
|
104
|
+
if line_count >= line_limit
|
105
|
+
line_breakpoint = i
|
106
|
+
break
|
107
|
+
end
|
108
|
+
else
|
109
|
+
line_count += 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
summary = content.lines.to_a[0, line_breakpoint].join
|
114
|
+
|
115
|
+
# The summary may be missing some key items needed to render properly.
|
116
|
+
# So search the rest of the content and add it to the summary.
|
117
|
+
content.lines.with_index(line_breakpoint) do |line, i|
|
118
|
+
# Add lines containing destination urls.
|
119
|
+
if line =~ /^\[[^\]]+\]:/
|
120
|
+
summary << "\n#{line}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
summary = @model.collection.master.render(summary)
|
125
|
+
Ruhoh::Converter.convert(summary, id)
|
126
|
+
end
|
127
|
+
|
128
|
+
def next
|
129
|
+
return unless id
|
130
|
+
all_cache = @model.collection.all
|
131
|
+
index = all_cache.index {|p| p["id"] == id}
|
132
|
+
return unless index && (index-1 >= 0)
|
133
|
+
_next = all_cache[index-1]
|
134
|
+
return unless _next
|
135
|
+
_next
|
136
|
+
end
|
137
|
+
|
138
|
+
def previous
|
139
|
+
return unless id
|
140
|
+
all_cache = @model.collection.all
|
141
|
+
index = all_cache.index {|p| p["id"] == id}
|
142
|
+
return unless index && (index+1 >= 0)
|
143
|
+
prev = all_cache[index+1]
|
144
|
+
return unless prev
|
145
|
+
prev
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class ModelView < SimpleDelegator
|
150
|
+
include ModelViewable
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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
|