smallcage 0.0.8

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 (71) hide show
  1. data/History.txt +15 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +70 -0
  4. data/README.txt +1 -0
  5. data/Rakefile +4 -0
  6. data/bin/smc +136 -0
  7. data/config/hoe.rb +70 -0
  8. data/config/requirements.rb +17 -0
  9. data/lib/smallcage/commands/Manifest.erb +19 -0
  10. data/lib/smallcage/commands/auto.rb +52 -0
  11. data/lib/smallcage/commands/clean.rb +24 -0
  12. data/lib/smallcage/commands/import.rb +212 -0
  13. data/lib/smallcage/commands/manifest.rb +39 -0
  14. data/lib/smallcage/commands/server.rb +24 -0
  15. data/lib/smallcage/commands/update.rb +40 -0
  16. data/lib/smallcage/erb_base.rb +16 -0
  17. data/lib/smallcage/loader.rb +239 -0
  18. data/lib/smallcage/misc.rb +13 -0
  19. data/lib/smallcage/renderer.rb +19 -0
  20. data/lib/smallcage/runner.rb +36 -0
  21. data/lib/smallcage/version.rb +9 -0
  22. data/lib/smallcage.rb +22 -0
  23. data/log/debug.log +0 -0
  24. data/project/default/_smc/helpers/base_helper.rb +34 -0
  25. data/project/default/_smc/helpers/site_helper.rb +5 -0
  26. data/project/default/_smc/templates/default.rhtml +5 -0
  27. data/project/default/_smc/templates/footer.rhtml +0 -0
  28. data/project/default/_smc/templates/header.rhtml +0 -0
  29. data/project/nkf/_smc/filters/filters.yml +3 -0
  30. data/project/nkf/_smc/filters/nkf_filter.rb +15 -0
  31. data/project/relpath/_smc/filters/filters.yml +2 -0
  32. data/project/relpath/_smc/filters/relpath_filter.rb +13 -0
  33. data/project/standard/_dir.smc +2 -0
  34. data/project/standard/_smc/helpers/menu_helper.rb +23 -0
  35. data/project/standard/_smc/templates/footer.rhtml +12 -0
  36. data/project/standard/_smc/templates/header.rhtml +35 -0
  37. data/project/standard/_smc/templates/redirect.rhtml +13 -0
  38. data/project/standard/_smc/templates/sidebar.rhtml +9 -0
  39. data/project/standard/_smc/templates/topic_path.rhtml +6 -0
  40. data/project/standard/about/_dir.smc +1 -0
  41. data/project/standard/about/index.html.smc +3 -0
  42. data/project/standard/common/css/default.css +97 -0
  43. data/project/standard/common/css/print.css +0 -0
  44. data/project/standard/index.html.smc +3 -0
  45. data/project/standard/sample1/_dir.smc +1 -0
  46. data/project/standard/sample1/index.html.smc +7 -0
  47. data/project/standard/sample1/index2.html.smc +5 -0
  48. data/project/standard/sample1/redirect.html.smc +2 -0
  49. data/project/standard/sample2/_dir.smc +1 -0
  50. data/project/standard/sample2/index.html.smc +3 -0
  51. data/script/destroy +14 -0
  52. data/script/destroy.cmd +1 -0
  53. data/script/generate +14 -0
  54. data/script/generate.cmd +1 -0
  55. data/setup.rb +1585 -0
  56. data/spec/data/htdocs1/_dir.smc +0 -0
  57. data/spec/data/htdocs1/a/b/c/index.html.smc +1 -0
  58. data/spec/import_spec.rb +20 -0
  59. data/spec/loader_spec.rb +41 -0
  60. data/spec/manifest_spec.rb +32 -0
  61. data/spec/misc_spec.rb +25 -0
  62. data/spec/smallcage_spec.rb +34 -0
  63. data/spec/spec.opts +1 -0
  64. data/spec/spec_helper.rb +9 -0
  65. data/tasks/deployment.rake +27 -0
  66. data/tasks/environment.rake +7 -0
  67. data/tasks/rspec.rake +21 -0
  68. data/tasks/website.rake +9 -0
  69. data/test/test_helper.rb +2 -0
  70. data/test/test_smallcage.rb +11 -0
  71. metadata +132 -0
@@ -0,0 +1,24 @@
1
+ require 'webrick'
2
+
3
+ module SmallCage::Commands
4
+ class Server
5
+ def self.execute(opts)
6
+ document_root = opts[:path]
7
+ port = opts[:port]
8
+
9
+ server = WEBrick::HTTPServer.new({
10
+ :DocumentRoot => document_root,
11
+ :Port => port
12
+ })
13
+
14
+ WEBrick::HTTPServlet::FileHandler.remove_handler("cgi")
15
+ WEBrick::HTTPServlet::FileHandler.remove_handler("rhtml")
16
+
17
+ ['INT', 'TERM'].each do |signal|
18
+ Signal.trap(signal){ server.shutdown }
19
+ end
20
+ server.start
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ module SmallCage::Commands
2
+ class Update
3
+ def self.execute(opts)
4
+ self.new(opts).execute
5
+ end
6
+
7
+ def initialize(opts)
8
+ @opts = opts
9
+ end
10
+
11
+ def execute
12
+ target = Pathname.new(@opts[:path])
13
+ unless target.exist?
14
+ raise "target directory or file does not exist.: " + target.to_s
15
+ end
16
+
17
+ loader = SmallCage::Loader.new(target)
18
+ renderer = SmallCage::Renderer.new(loader)
19
+
20
+ loader.each_smc_obj do |obj|
21
+ result = renderer.render(obj["template"], obj)
22
+
23
+ filters = loader.filters("after_rendering_filters")
24
+ filters.each do |f|
25
+ result = f.after_rendering_filter(obj, result)
26
+ end
27
+
28
+ output_result(obj, result)
29
+ puts obj["uri"] if @opts[:quiet].nil?
30
+ end
31
+ end
32
+
33
+ def output_result(obj, str)
34
+ open(obj["path"], "w") do |io|
35
+ io << str
36
+ end
37
+ end
38
+ private :output_result
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+
2
+ class SmallCage::ErbBase
3
+ def initialize(loader, renderer, obj)
4
+ @loader, @renderer, @obj = loader, renderer, obj
5
+ end
6
+
7
+ def method_missing(name)
8
+ n = name.to_s
9
+
10
+ return @obj[n] unless @obj[n].nil?
11
+ return @obj["strings"][0] if n == "body" && ! @obj["strings"][0].nil?
12
+
13
+ # render if template file exists. or return nil.
14
+ return @renderer.render(name, @obj)
15
+ end
16
+ end
@@ -0,0 +1,239 @@
1
+ module SmallCage
2
+ class Loader
3
+ DEFAULT_TEMPLATE = "default"
4
+ DIR_PROP_FILE = "_dir.smc"
5
+ MAX_DEPTH = 100
6
+
7
+ attr_reader :root, :target, :erb_base
8
+
9
+ def initialize(target)
10
+ target = Pathname.new(target.to_s.strip.gsub(%r{(.+)/$}, '\1'))
11
+ target = real_target(target)
12
+
13
+ @target = target # absolute
14
+ @root = SmallCage::Loader.find_root(target) # absolute
15
+ @templates_dir = @root + "_smc/templates"
16
+ @helpers_dir = @root + "_smc/helpers"
17
+ @filters_dir = @root + "_smc/filters"
18
+ @erb_base = load_erb_base
19
+ @filters = load_filters
20
+ end
21
+
22
+ # return root dir Pathname object.
23
+ def self.find_root(path, depth = MAX_DEPTH)
24
+ unless path.exist?
25
+ raise "Not found: " + path.to_s
26
+ end
27
+ d = path.realpath
28
+
29
+ if d.file?
30
+ d = d.parent
31
+ end
32
+
33
+ i = 0
34
+ loop do
35
+ if d.join("_smc").directory?
36
+ return d
37
+ end
38
+ break if d.root?
39
+ d = d.parent
40
+
41
+ i += 1
42
+ break if depth <= i
43
+ end
44
+
45
+ raise "Root not found: " + path
46
+ end
47
+
48
+ def load(path)
49
+ unless path.exist?
50
+ raise "Not found: " + path.to_s
51
+ end
52
+ path = path.realpath
53
+ unless path.to_s[0...@root.to_s.length] == @root.to_s
54
+ raise "Illegal path: " + path.to_s + " , " + @root.to_s
55
+ end
56
+
57
+ result = {}
58
+ if path.file?
59
+ path_smc = path
60
+ path_out = Pathname.new(strip_ext(path))
61
+ uri_smc = to_uri(path)
62
+ uri_out = strip_ext(uri_smc)
63
+ source_path = path
64
+
65
+ result["dirs"] = load_dirs(path)
66
+ result["template"] = DEFAULT_TEMPLATE
67
+ else
68
+ path_smc = nil
69
+ path_out = path
70
+ uri_smc = nil
71
+ uri_out = to_uri(path)
72
+ uri_out += "/" unless uri_out =~ %r{/$}
73
+ source_path = path + DIR_PROP_FILE
74
+
75
+ if source_path.file?
76
+ path_smc = source_path
77
+ uri_smc = to_uri(source_path)
78
+ end
79
+ end
80
+
81
+ add_smc_method(path_out, path_smc)
82
+ add_smc_method(uri_out, uri_smc)
83
+
84
+ result["path"] = path_out
85
+ result["uri"] = uri_out
86
+ result["arrays"] = []
87
+ result["strings"] = []
88
+
89
+ return result unless source_path.exist?
90
+
91
+ source = source_path.read
92
+ return result if source.strip.empty?
93
+
94
+ obj = YAML.load_stream(source)
95
+ return result if obj.nil?
96
+
97
+ obj.documents.each do |o|
98
+ if o.is_a? Hash
99
+ result = result.merge(o)
100
+ elsif o.is_a? Array
101
+ result["arrays"] << o
102
+ else
103
+ result["strings"] << o.to_s
104
+ end
105
+ end
106
+
107
+ return result
108
+ end
109
+
110
+ def load_dirs(path)
111
+ result = []
112
+ loop do
113
+ path = path.parent
114
+ result.unshift load(path)
115
+ break if path.join("_smc").directory?
116
+ raise "Root directory not found!" if path.root?
117
+ end
118
+ return result
119
+ end
120
+
121
+ def template_path(name)
122
+ result = @templates_dir + "#{name}.rhtml"
123
+ return nil unless result.file?
124
+ return result
125
+ end
126
+
127
+ def each_smc_obj
128
+ each_smc_file do |path|
129
+ next if path.directory?
130
+ next if path.basename.to_s == DIR_PROP_FILE
131
+ obj = load(path)
132
+ yield obj
133
+ end
134
+ end
135
+
136
+ def each_smc_file
137
+ if @target.directory?
138
+ p = Pathname.new(@target)
139
+ Dir.chdir(@target) do
140
+ Dir.glob("**/*.smc") do |f|
141
+ yield p + f
142
+ end
143
+ end
144
+ else
145
+ yield @target
146
+ end
147
+ end
148
+ private :each_smc_file
149
+
150
+ def real_target(target)
151
+ return target.realpath if target.directory?
152
+ return target.realpath if target.file? and target.to_s =~ /\.smc$/
153
+
154
+ tmp = Pathname.new(target.to_s + ".smc")
155
+ return tmp.realpath if tmp.file?
156
+
157
+ raise "Target not found: " + target.to_s
158
+ end
159
+ private :real_target
160
+
161
+
162
+ def load_erb_base
163
+ result = Class.new(SmallCage::ErbBase)
164
+ class_names = load_classes(@helpers_dir, %r{([^/]+_helper)\.rb$})
165
+ class_names.each do |class_name|
166
+ result.class_eval("include SmallCage::#{class_name}")
167
+ end
168
+ return result
169
+ end
170
+ private :load_erb_base
171
+
172
+ def load_classes(dir, rex)
173
+ class_names = []
174
+ Dir.entries(dir).sort.each do |h|
175
+ next unless h =~ rex
176
+ require "#{dir}/#{h}"
177
+ class_names << $1.camelize
178
+ end
179
+ return class_names
180
+ end
181
+ private :load_classes
182
+
183
+ def filters(name)
184
+ if @filters[name].nil?
185
+ return []
186
+ end
187
+ return @filters[name]
188
+ end
189
+
190
+ def load_filters
191
+ result = {}
192
+ return {} unless @filters_dir.directory?
193
+
194
+ load_classes(@filters_dir, %r{([^/]+_filter)\.rb$})
195
+
196
+ config = load_filters_config
197
+ config.each do |filter_type,filter_list|
198
+ result[filter_type] = []
199
+ filter_list.each do |fc|
200
+ fc = { "name" => fc } if fc.is_a? String
201
+ klass = SmallCage.const_get(fc["name"].camelize)
202
+ result[filter_type] << klass.new(fc)
203
+ end
204
+ end
205
+ return result
206
+ end
207
+ private :load_filters
208
+
209
+ def load_filters_config
210
+ path = @filters_dir.join("filters.yml")
211
+ return {} unless path.file?
212
+ return YAML.load(path.read())
213
+ end
214
+ private :load_filters_config
215
+
216
+ def strip_ext(path)
217
+ path.to_s[0..-5]
218
+ end
219
+ private :strip_ext
220
+
221
+ def to_uri(path)
222
+ path.realpath.to_s[@root.to_s.length .. -1]
223
+ end
224
+ private :to_uri
225
+
226
+ def add_smc_method(obj, value)
227
+ obj.instance_eval do
228
+ @__smallcage ||= {}
229
+ @__smallcage[:smc] = value
230
+ end
231
+
232
+ def obj.smc
233
+ return @__smallcage.nil? ? nil : @__smallcage[:smc]
234
+ end
235
+ end
236
+ private :add_smc_method
237
+
238
+ end
239
+ end
@@ -0,0 +1,13 @@
1
+
2
+ # From active-support/inflector.rb
3
+ class String
4
+ def camelize(first_letter_in_uppercase = true)
5
+ s = self
6
+ if first_letter_in_uppercase
7
+ s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
8
+ else
9
+ s[0..0] + s.camelize[1..-1]
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,19 @@
1
+ class SmallCage::Renderer
2
+
3
+ def initialize(loader)
4
+ @loader = loader
5
+ end
6
+
7
+ def render(name, obj)
8
+ path = @loader.template_path(name)
9
+ return nil if path.nil?
10
+ return render_string(path.read, obj)
11
+ end
12
+
13
+ def render_string(str, obj)
14
+ erb_class = ERB.new(str, nil, '-').def_class(@loader.erb_base, "erb")
15
+ result = erb_class.new(@loader, self, obj).erb
16
+ return result
17
+ end
18
+
19
+ end
@@ -0,0 +1,36 @@
1
+ module SmallCage
2
+ class Runner
3
+ def self.run(opts)
4
+ Runner.new(opts).send(opts[:command])
5
+ end
6
+
7
+ def initialize(opts)
8
+ @opts = opts
9
+ end
10
+
11
+ def update
12
+ SmallCage::Commands::Update.execute(@opts)
13
+ end
14
+
15
+ def clean
16
+ SmallCage::Commands::Clean.execute(@opts)
17
+ end
18
+
19
+ def server
20
+ SmallCage::Commands::Server.execute(@opts)
21
+ end
22
+
23
+ def auto
24
+ SmallCage::Commands::Auto.execute(@opts)
25
+ end
26
+
27
+ def import
28
+ SmallCage::Commands::Import.execute(@opts)
29
+ end
30
+
31
+ def manifest
32
+ SmallCage::Commands::Manifest.execute(@opts)
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module SmallCage #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 8
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/smallcage.rb ADDED
@@ -0,0 +1,22 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'yaml'
4
+ require 'erb'
5
+ require 'pathname'
6
+ require 'open-uri'
7
+ require 'fileutils'
8
+
9
+ require 'smallcage/version'
10
+ require 'smallcage/misc'
11
+ require 'smallcage/loader'
12
+ require 'smallcage/erb_base'
13
+ require 'smallcage/renderer'
14
+ require 'smallcage/runner'
15
+
16
+ require 'smallcage/commands/update'
17
+ require 'smallcage/commands/clean'
18
+ require 'smallcage/commands/server'
19
+ require 'smallcage/commands/auto'
20
+ require 'smallcage/commands/import'
21
+ require 'smallcage/commands/manifest'
22
+
data/log/debug.log ADDED
File without changes
@@ -0,0 +1,34 @@
1
+ module SmallCage
2
+ module BaseHelper
3
+ include ERB::Util
4
+
5
+ def _glob(relpath, rex)
6
+ base_dir = Pathname.new(@obj["path"]).parent
7
+ base_dir = base_dir.join(relpath)
8
+
9
+ entries = Dir.glob("#{base_dir}/**/*")
10
+ result = []
11
+ entries.each do |path|
12
+ result << path if path.to_s =~ rex
13
+ end
14
+ return result.sort
15
+ end
16
+
17
+ def _with(o)
18
+ tmpobj = @obj
19
+ @obj = o
20
+ yield
21
+ @obj = tmpobj
22
+ end
23
+
24
+ def _load(path)
25
+ path = Pathname.new(path)
26
+ @loader.load(path)
27
+ end
28
+
29
+ def _erb(body)
30
+ @renderer.render_string(body, @obj)
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module SmallCage
2
+ module SiteHelper
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ <%= header %>
2
+
3
+ <%= body %>
4
+
5
+ <%= footer %>
File without changes
File without changes
@@ -0,0 +1,3 @@
1
+ after_rendering_filters:
2
+ - name: nkf_filter
3
+ args: "-W -s" # UTF-8 to SJIS
@@ -0,0 +1,15 @@
1
+ module SmallCage
2
+ require "nkf"
3
+
4
+ class NkfFilter
5
+
6
+ def initialize(opts)
7
+ @args = opts["args"]
8
+ end
9
+
10
+ def after_rendering_filter(obj, str)
11
+ return NKF.nkf(@args, str)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ after_rendering_filters:
2
+ - name: relpath_filter
@@ -0,0 +1,13 @@
1
+ module SmallCage
2
+ class RelpathFilter
3
+
4
+ def initialize(opts)
5
+ end
6
+
7
+ def after_rendering_filter(obj, str)
8
+ relpath = "../" * (obj["dirs"].size - 1)
9
+ return str.gsub(%r{="/}, "=\"#{relpath}")
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ lang: en
2
+ topic: Home
@@ -0,0 +1,23 @@
1
+ module SmallCage
2
+ module MenuHelper
3
+
4
+ def menu_active(name)
5
+ p = @obj["menu_path"]
6
+ p ||= uri
7
+ return p =~ %r{^/#{name}/} ? "active" : "inactive"
8
+ end
9
+
10
+ def menu_active_rex(rex)
11
+ p = @obj["menu_path"]
12
+ p ||= uri
13
+ return p =~ rex ? "active" : "inactive"
14
+ end
15
+
16
+ def topic_dirs
17
+ result = @obj["dirs"].dup
18
+ result.reject! {|d| d["topic"].nil? }
19
+ return result
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ </div>
2
+
3
+ <%= sidebar %>
4
+
5
+ </div>
6
+
7
+ <div class="footer">
8
+ <div class="copyright">&copy; 20XX-<%= Time.now.year %> Site Owner All rights reserved.</div>
9
+ </div>
10
+
11
+ </body>
12
+ </html>
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja-JP" lang="ja-JP">
4
+ <head>
5
+
6
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7
+ <meta name="keywords" content="" />
8
+ <%- unless description.nil? -%>
9
+ <meta name="description" content="<%=h description %>" />
10
+ <%- end -%>
11
+
12
+ <link rev="made" href="mailto:info@example.com" />
13
+ <link rel="index" href="./index.html" />
14
+ <link rel="stylesheet" type="text/css" href="/common/css/default.css" media="screen"/>
15
+ <link rel="stylesheet" type="text/css" href="/common/css/print.css" media="print" />
16
+ <link rel="shortcut icon" href="/common/favicon.ico" />
17
+
18
+ <title><% if uri !~ %r{^/index.html$} %><%=h title %> | <% end %>Standard Site Template</title>
19
+ </head>
20
+ <body>
21
+
22
+ <div class="header">
23
+ <h1><a href="/index.html">Standard Site Template</a></h1>
24
+
25
+ <div class="topicpath">
26
+ <%= topic_path %>
27
+ </div>
28
+ </div>
29
+
30
+
31
+ <div class="container">
32
+
33
+ <div class="contents">
34
+
35
+ <h2><%=h title %></h2>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja-JP" lang="ja-JP">
6
+ <head>
7
+ <title></title>
8
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
9
+ <meta http-equiv="refresh" content="0;URL=<%= redirect_uri %>">
10
+ </head>
11
+ <body>
12
+ </body>
13
+ </html>
@@ -0,0 +1,9 @@
1
+ <div class="sidebar">
2
+ <ul>
3
+ <li class="<%= menu_active_rex(%r{^/index.html$}) %>"><a href="/index.html">Home</a></li>
4
+ <li class="<%= menu_active("sample1") %>"><a href="/sample1/index.html">Sample 1</a></li>
5
+ <li class="<%= menu_active("sample2") %>"><a href="/sample2/index.html">Sample 2</a></li>
6
+ <li class="<%= menu_active("dummy") %>"><a href="/dummy/index.html">Dummy</a></li>
7
+ <li class="<%= menu_active("about") %>"><a href="/about/index.html">About</a></li>
8
+ </ul>
9
+ </div>
@@ -0,0 +1,6 @@
1
+ <% topic_dirs.each do |d| %>
2
+ <a href="<%= d["uri"]%>index.html"><%= d["topic"] %></a>
3
+ <% if topic_dirs.last != d %>
4
+ <span class="delimiter"> &gt; </span>
5
+ <% end %>
6
+ <% end %>
@@ -0,0 +1 @@
1
+ topic: About
@@ -0,0 +1,3 @@
1
+ title: About This Site
2
+ ---
3
+ <p>Description about this site.</p>