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/client.rb
CHANGED
@@ -40,8 +40,6 @@ class Ruhoh
|
|
40
40
|
return server if %w(s serve server).include?(cmd)
|
41
41
|
|
42
42
|
@ruhoh = Ruhoh.new
|
43
|
-
@ruhoh.setup
|
44
|
-
@ruhoh.setup_paths
|
45
43
|
@ruhoh.setup_plugins
|
46
44
|
|
47
45
|
return __send__(cmd) if respond_to?(cmd)
|
@@ -136,7 +134,7 @@ class Ruhoh
|
|
136
134
|
end
|
137
135
|
|
138
136
|
if Ruhoh::Publish.const_defined?(service.to_sym)
|
139
|
-
publish_config = Ruhoh::Parse.data_file(@ruhoh.base, "publish") || {}
|
137
|
+
publish_config = Ruhoh::Parse.data_file(@ruhoh.cascade.base, "publish") || {}
|
140
138
|
Ruhoh::Publish.const_get(service.to_sym).new.run(@args, publish_config[service.downcase])
|
141
139
|
else
|
142
140
|
Ruhoh::Friend.say {
|
data/lib/ruhoh/collections.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
module Ruhoh::Base ; end
|
1
2
|
module Ruhoh::Resources ; end
|
2
3
|
# Require all the resources
|
3
4
|
FileUtils.cd(File.join(File.dirname(__FILE__), 'base')) do
|
@@ -71,7 +72,7 @@ class Ruhoh
|
|
71
72
|
def discover
|
72
73
|
results = Set.new
|
73
74
|
|
74
|
-
@ruhoh.cascade.each do |h|
|
75
|
+
@ruhoh.cascade.paths.each do |h|
|
75
76
|
FileUtils.cd(h["path"]) do
|
76
77
|
results += Dir['*'].select { |x|
|
77
78
|
File.directory?(x) && !["plugins", 'compiled'].include?(x)
|
data/lib/ruhoh/config.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
class Config < SimpleDelegator
|
3
|
+
include Observable
|
4
|
+
|
5
|
+
def initialize(ruhoh)
|
6
|
+
@ruhoh = ruhoh
|
7
|
+
@data = {}
|
8
|
+
super(@data)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Regenerate the config data
|
12
|
+
def touch
|
13
|
+
data = @ruhoh.cascade.merge_data_file('config') || {}
|
14
|
+
data = Ruhoh::Utils.deep_merge(data, collections_config)
|
15
|
+
data = Ruhoh::Utils.deep_merge(data, find_theme_path)
|
16
|
+
|
17
|
+
@data.clear
|
18
|
+
@data.merge!(data)
|
19
|
+
|
20
|
+
Time.default_format = @data['date_format']
|
21
|
+
@data["compiled_path"] = File.expand_path(@data["compiled_path"])
|
22
|
+
|
23
|
+
changed
|
24
|
+
notify_observers(@data)
|
25
|
+
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def base_path
|
30
|
+
return '/' unless (@ruhoh.env == 'production')
|
31
|
+
|
32
|
+
@data['base_path'] += "/" unless @data['base_path'][-1] == '/'
|
33
|
+
string = @data['base_path'].chomp('/').reverse.chomp('/').reverse
|
34
|
+
return '/' if string.empty? || string == '/'
|
35
|
+
"/#{ string }/"
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def find_theme_path
|
41
|
+
theme_name = @data.find { |resource, data| data.is_a?(Hash) && data['use'] == "theme" }
|
42
|
+
if theme_name
|
43
|
+
Ruhoh::Friend.say { plain "Using theme: \"#{theme_name[0]}\""}
|
44
|
+
{ "_theme_collection" => theme_name[0] }
|
45
|
+
else
|
46
|
+
{ "_theme_collection" => nil }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Quick and dirty way to scan for config files in collection folders.
|
51
|
+
# This is needed because we don't know which collection defines itself as a theme
|
52
|
+
# so we'll scan for any configs and merge the data to find the theme folder.
|
53
|
+
def collections_config
|
54
|
+
data = {}
|
55
|
+
@ruhoh.cascade.paths.map{ |a| a['path'] }.each do |path|
|
56
|
+
FileUtils.cd(path) {
|
57
|
+
Dir["*/config.*"].each { |id|
|
58
|
+
next unless File.exist?(id) && FileTest.file?(id)
|
59
|
+
data = Ruhoh::Utils.deep_merge(data, (Ruhoh::Parse.data_file(File.realpath(id)) || {}))
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
data
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/ruhoh/parse.rb
CHANGED
@@ -42,13 +42,15 @@ class Ruhoh
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def self.data_file(*args)
|
45
|
-
|
45
|
+
filepath = File.__send__(:join, args)
|
46
|
+
if File.extname(filepath).to_s.empty?
|
47
|
+
path = nil
|
48
|
+
["#{ filepath }.json", "#{ filepath }.yml", "#{ filepath }.yaml"].each do |result|
|
49
|
+
filepath = path = result and break if File.exist?(result)
|
50
|
+
end
|
46
51
|
|
47
|
-
|
48
|
-
["#{ base }.json", "#{ base }.yml", "#{ base }.yaml"].each do |result|
|
49
|
-
filepath = result and break if File.exist?(result)
|
52
|
+
return nil unless path
|
50
53
|
end
|
51
|
-
return nil unless filepath
|
52
54
|
|
53
55
|
file = File.open(filepath, 'r:UTF-8') { |f| f.read }
|
54
56
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Ruhoh::Plugins
|
2
|
+
class Initializer
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize name, &block
|
6
|
+
raise ArgumentError, "block required for initializer '#{name}'" unless block_given?
|
7
|
+
@name, @block = name, block
|
8
|
+
end
|
9
|
+
|
10
|
+
def run *args
|
11
|
+
raise "Initializer '#{name}' need to be bound" unless context
|
12
|
+
context.instance_exec *args, &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def bind ctx
|
16
|
+
@context = ctx
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :block, :context
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'ruhoh/plugins/initializer'
|
2
|
+
|
3
|
+
module Ruhoh::Plugins
|
4
|
+
module Plugin
|
5
|
+
def self.included base
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.run_all(context, *args)
|
10
|
+
initializers.each do |i|
|
11
|
+
i.bind(context).run *args
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def self.initializers
|
18
|
+
@initializers ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
def initializer name, &block
|
23
|
+
Plugin.initializers << Initializer.new(name, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -5,15 +5,11 @@ class Ruhoh
|
|
5
5
|
# to properly omit drafts and other development-only settings.
|
6
6
|
def self.compile(target=nil)
|
7
7
|
ruhoh = Ruhoh.new
|
8
|
-
ruhoh.setup
|
9
8
|
ruhoh.env = 'production'
|
10
|
-
ruhoh.setup_paths
|
11
9
|
ruhoh.setup_plugins
|
12
|
-
|
10
|
+
|
13
11
|
if target
|
14
|
-
ruhoh.
|
15
|
-
elsif ruhoh.config["compiled"]
|
16
|
-
ruhoh.paths.compiled = ruhoh.config["compiled"]
|
12
|
+
ruhoh.config['compiled_path'] = File.expand_path(target)
|
17
13
|
end
|
18
14
|
|
19
15
|
ruhoh.compile
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ruhoh/programs/watch'
|
2
|
+
require 'ruhoh/ui/dashboard'
|
2
3
|
class Ruhoh
|
3
4
|
module Program
|
4
5
|
# Public: A program for running ruhoh as a rack application
|
@@ -17,9 +18,7 @@ class Ruhoh
|
|
17
18
|
opts[:env] ||= 'development'
|
18
19
|
|
19
20
|
ruhoh = Ruhoh.new
|
20
|
-
ruhoh.setup
|
21
21
|
ruhoh.env = opts[:env]
|
22
|
-
ruhoh.setup_paths
|
23
22
|
ruhoh.setup_plugins unless opts[:enable_plugins] == false
|
24
23
|
|
25
24
|
# initialize the routes dictionary for all page resources.
|
@@ -52,6 +51,10 @@ class Ruhoh
|
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
54
|
+
map '/dash' do
|
55
|
+
run Ruhoh::UI::Dashboard.new(ruhoh)
|
56
|
+
end
|
57
|
+
|
55
58
|
# The generic Page::Previewer is used to render any/all page-like resources,
|
56
59
|
# since they likely have arbitrary urls based on permalink settings.
|
57
60
|
map '/' do
|
data/lib/ruhoh/programs/watch.rb
CHANGED
@@ -7,12 +7,10 @@ class Ruhoh
|
|
7
7
|
# The observer triggers data regeneration as files change
|
8
8
|
# in order to keep the data up to date in real time.
|
9
9
|
def self.watch(ruhoh)
|
10
|
-
ruhoh.ensure_setup
|
11
|
-
|
12
10
|
Ruhoh::Friend.say {
|
13
|
-
cyan "=> Start watching: #{ruhoh.
|
11
|
+
cyan "=> Start watching: #{ruhoh.cascade.base}"
|
14
12
|
}
|
15
|
-
dw = DirectoryWatcher.new(ruhoh.
|
13
|
+
dw = DirectoryWatcher.new(ruhoh.cascade.base, {
|
16
14
|
:glob => "**/*",
|
17
15
|
:pre_load => true
|
18
16
|
})
|
@@ -21,14 +19,14 @@ class Ruhoh
|
|
21
19
|
args.each do |event|
|
22
20
|
ruhoh.cache.delete(event['path'])
|
23
21
|
|
24
|
-
path = event['path'].gsub(ruhoh.
|
22
|
+
path = event['path'].gsub(ruhoh.cascade.base + '/', '')
|
25
23
|
|
26
24
|
Ruhoh::Friend.say {
|
27
25
|
yellow "Watch [#{Time.now.strftime("%H:%M:%S")}] [Update #{path}] : #{args.size} files changed"
|
28
26
|
}
|
29
27
|
|
30
28
|
if %w{ config.json config.yml config.yaml }.include?(path)
|
31
|
-
ruhoh.config
|
29
|
+
ruhoh.config.touch
|
32
30
|
else
|
33
31
|
separator = File::ALT_SEPARATOR ?
|
34
32
|
%r{#{ File::SEPARATOR }|#{ File::ALT_SEPARATOR }} :
|
data/lib/ruhoh/publish/rsync.rb
CHANGED
@@ -22,9 +22,9 @@ class Ruhoh
|
|
22
22
|
if @config["command"]
|
23
23
|
system(@config["command"])
|
24
24
|
else
|
25
|
-
system('rsync', File.join(ruhoh.
|
25
|
+
system('rsync', File.join(ruhoh.config['compiled_path'], '.'), '-avz', '--delete', '--exclude', '.git', remote)
|
26
26
|
end
|
27
|
-
FileUtils.rm_r(ruhoh.
|
27
|
+
FileUtils.rm_r(ruhoh.config['compiled_path'])
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
@@ -2,24 +2,45 @@ module Ruhoh::Resources::Data
|
|
2
2
|
class Collection
|
3
3
|
include Ruhoh::Base::Collectable
|
4
4
|
|
5
|
+
def glob
|
6
|
+
"*"
|
7
|
+
end
|
8
|
+
|
9
|
+
def dictionary
|
10
|
+
resource_name == "data" ?
|
11
|
+
_support_legacy_api :
|
12
|
+
_support_new_data_api
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def _support_new_data_api
|
18
|
+
data = {}
|
19
|
+
files.values.each do |pointer|
|
20
|
+
name = File.basename(pointer["id"], File.extname(pointer["id"]))
|
21
|
+
data[name] = Ruhoh::Parse.data_file(pointer["realpath"]) || {}
|
22
|
+
end
|
23
|
+
|
24
|
+
data
|
25
|
+
end
|
26
|
+
|
5
27
|
# TODO: This is ugly but it works.
|
6
28
|
# Should handle data extensions in the cascade more elegantly
|
7
|
-
def
|
8
|
-
|
29
|
+
def _support_legacy_api
|
30
|
+
found_paths = []
|
9
31
|
|
10
|
-
@ruhoh.cascade.
|
32
|
+
@ruhoh.cascade.paths.each do |h|
|
11
33
|
path_prefix = File.join(h["path"], resource_name)
|
12
34
|
|
13
35
|
["#{ path_prefix }.json", "#{ path_prefix }.yml", "#{ path_prefix }.yaml"].each do |file|
|
14
|
-
|
36
|
+
found_paths << path_prefix and break if File.exist?(file)
|
15
37
|
end
|
16
|
-
|
17
|
-
break if found_path_prefix
|
18
38
|
end
|
19
39
|
|
20
|
-
|
40
|
+
data = {}
|
41
|
+
found_paths.each { |path| data.merge!(Ruhoh::Parse.data_file(path) || {}) }
|
21
42
|
|
22
|
-
|
43
|
+
data
|
23
44
|
end
|
24
45
|
end
|
25
|
-
end
|
46
|
+
end
|
@@ -24,7 +24,7 @@ module Ruhoh::Resources::Layouts
|
|
24
24
|
exit
|
25
25
|
} if name.nil?
|
26
26
|
|
27
|
-
filename = File.join((@ruhoh.
|
27
|
+
filename = File.join((@ruhoh.cascade.theme || @ruhoh.cascade.base), "layouts", name.gsub(/\s/, '-').downcase) + ".html"
|
28
28
|
|
29
29
|
if File.exist?(filename)
|
30
30
|
abort("Create new layout: aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
|
@@ -105,8 +105,8 @@ module Ruhoh::Resources::Pages
|
|
105
105
|
|
106
106
|
name = "#{name}-#{@iterator}" unless @iterator.zero?
|
107
107
|
filename = opts[:draft] ?
|
108
|
-
File.join(@ruhoh.
|
109
|
-
File.join(@ruhoh.
|
108
|
+
File.join(@ruhoh.cascade.base, @collection.resource_name, "drafts", "#{name}#{ext}") :
|
109
|
+
File.join(@ruhoh.cascade.base, @collection.resource_name, "#{name}#{ext}")
|
110
110
|
@iterator += 1
|
111
111
|
end while File.exist?(filename)
|
112
112
|
|
@@ -1,27 +1,8 @@
|
|
1
|
+
require 'ruhoh/base/routable'
|
1
2
|
module Ruhoh::Resources::Pages
|
2
|
-
module Routable
|
3
|
-
def routes
|
4
|
-
return @routes if @routes
|
5
|
-
@routes = {}
|
6
|
-
dictionary
|
7
|
-
@routes
|
8
|
-
end
|
9
|
-
|
10
|
-
def routes_add(route, pointer)
|
11
|
-
@routes ||= {}
|
12
|
-
@routes[route] = pointer
|
13
|
-
end
|
14
|
-
|
15
|
-
def routes_delete(pointer)
|
16
|
-
return unless @routes
|
17
|
-
route = @routes.find{ |k, v| v == pointer }
|
18
|
-
@routes.delete(route[0]) if route
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
3
|
class Collection
|
23
4
|
include Ruhoh::Base::Collectable
|
24
|
-
include Routable
|
5
|
+
include Ruhoh::Base::Routable
|
25
6
|
|
26
7
|
# model observer callback.
|
27
8
|
def update(model_data)
|