alula 0.2.3 → 0.4.0b

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 (182) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +7 -0
  3. data/Guardfile +9 -0
  4. data/Rakefile +12 -1
  5. data/VERSION +1 -1
  6. data/alula.gemspec +20 -4
  7. data/lib/alula/attachment_processor.rb +77 -0
  8. data/lib/alula/cdn.rb +30 -0
  9. data/lib/alula/cdns/edgecast.rb +16 -0
  10. data/lib/alula/cdns/hosts.rb +14 -0
  11. data/lib/alula/cli.rb +90 -39
  12. data/lib/alula/compressors.rb +22 -10
  13. data/lib/alula/config.rb +141 -0
  14. data/lib/alula/content.rb +113 -0
  15. data/lib/alula/contents/attachment.rb +8 -0
  16. data/lib/alula/contents/item.rb +409 -0
  17. data/lib/alula/contents/metadata.rb +73 -0
  18. data/lib/alula/contents/page.rb +9 -0
  19. data/lib/alula/contents/post.rb +32 -0
  20. data/lib/alula/context.rb +72 -0
  21. data/lib/alula/core_ext.rb +5 -0
  22. data/lib/alula/core_ext/environment.rb +20 -0
  23. data/lib/alula/core_ext/filter.rb +20 -0
  24. data/lib/alula/core_ext/filters/smilies.rb +36 -0
  25. data/lib/alula/core_ext/manifest.rb +30 -0
  26. data/lib/alula/core_ext/tag.rb +100 -0
  27. data/lib/alula/core_ext/tags/attachment.rb +28 -0
  28. data/lib/alula/core_ext/tags/blockquote.rb +21 -0
  29. data/lib/alula/core_ext/tags/image.rb +48 -0
  30. data/lib/alula/core_ext/tags/locale.rb +17 -0
  31. data/lib/alula/core_ext/tags/video.rb +103 -0
  32. data/lib/alula/generator.rb +31 -0
  33. data/lib/alula/generators/feedbuilder.rb +44 -0
  34. data/lib/alula/generators/paginate.rb +88 -0
  35. data/lib/alula/generators/sitemap.rb +26 -0
  36. data/lib/alula/helpers.rb +2 -0
  37. data/lib/alula/helpers/addons.rb +12 -0
  38. data/lib/alula/helpers/assets.rb +56 -0
  39. data/lib/alula/helpers/url_helpers.rb +16 -0
  40. data/lib/alula/plugin.rb +32 -0
  41. data/lib/alula/processor.rb +86 -0
  42. data/lib/alula/processors/dummy.rb +24 -0
  43. data/lib/alula/processors/image.rb +52 -0
  44. data/lib/alula/processors/magick.rb +83 -0
  45. data/lib/alula/processors/video.rb +97 -0
  46. data/lib/alula/processors/zencoder.rb +199 -0
  47. data/lib/alula/progress.rb +95 -0
  48. data/lib/alula/progressbar.rb +66 -0
  49. data/lib/alula/site.rb +331 -262
  50. data/lib/alula/storage.rb +46 -0
  51. data/lib/alula/storages/file_item.rb +43 -0
  52. data/lib/alula/storages/filestorage.rb +96 -0
  53. data/lib/alula/storages/item.rb +12 -0
  54. data/lib/alula/support/commonlogger.rb +30 -0
  55. data/lib/alula/theme.rb +70 -13
  56. data/lib/alula/theme/layout.rb +56 -0
  57. data/lib/alula/theme/view.rb +43 -0
  58. data/lib/alula/version.rb +1 -1
  59. data/locales/en.yml +9 -0
  60. data/locales/fi.yml +10 -0
  61. data/locales/l10n/ar.yml +199 -0
  62. data/locales/l10n/az.yml +199 -0
  63. data/locales/l10n/bg.yml +199 -0
  64. data/locales/l10n/bn-IN.yml +182 -0
  65. data/locales/l10n/bs.yml +242 -0
  66. data/locales/l10n/ca.yml +199 -0
  67. data/locales/l10n/cs.yml +198 -0
  68. data/locales/l10n/csb.yml +210 -0
  69. data/locales/l10n/cy.yml +199 -0
  70. data/locales/l10n/da.yml +199 -0
  71. data/locales/l10n/de-AT.yml +203 -0
  72. data/locales/l10n/de-CH.yml +203 -0
  73. data/locales/l10n/de.yml +203 -0
  74. data/locales/l10n/dsb.yml +215 -0
  75. data/locales/l10n/el.yml +199 -0
  76. data/locales/l10n/en-AU.yml +205 -0
  77. data/locales/l10n/en-CA.yml +214 -0
  78. data/locales/l10n/en-GB.yml +205 -0
  79. data/locales/l10n/en-IN.yml +205 -0
  80. data/locales/l10n/en-US.yml +205 -0
  81. data/locales/l10n/en.yml +205 -0
  82. data/locales/l10n/eo.yml +201 -0
  83. data/locales/l10n/es-AR.yml +205 -0
  84. data/locales/l10n/es-CL.yml +199 -0
  85. data/locales/l10n/es-CO.yml +205 -0
  86. data/locales/l10n/es-MX.yml +205 -0
  87. data/locales/l10n/es-PE.yml +181 -0
  88. data/locales/l10n/es-VE.yml +205 -0
  89. data/locales/l10n/es.yml +199 -0
  90. data/locales/l10n/et.yml +199 -0
  91. data/locales/l10n/eu.yml +199 -0
  92. data/locales/l10n/fa.yml +199 -0
  93. data/locales/l10n/fi.yml +199 -0
  94. data/locales/l10n/fr-CA.yml +207 -0
  95. data/locales/l10n/fr-CH.yml +207 -0
  96. data/locales/l10n/fr.yml +222 -0
  97. data/locales/l10n/fur.yml +199 -0
  98. data/locales/l10n/gl-ES.yml +178 -0
  99. data/locales/l10n/gsw-CH.yml +199 -0
  100. data/locales/l10n/he.yml +201 -0
  101. data/locales/l10n/hi-IN.yml +199 -0
  102. data/locales/l10n/hi.yml +199 -0
  103. data/locales/l10n/hr.yml +237 -0
  104. data/locales/l10n/hsb.yml +214 -0
  105. data/locales/l10n/hu.yml +199 -0
  106. data/locales/l10n/id.yml +200 -0
  107. data/locales/l10n/is.yml +213 -0
  108. data/locales/l10n/it.yml +205 -0
  109. data/locales/l10n/ja.yml +197 -0
  110. data/locales/l10n/kn.yml +199 -0
  111. data/locales/l10n/ko.yml +197 -0
  112. data/locales/l10n/lo.yml +186 -0
  113. data/locales/l10n/lt.yml +182 -0
  114. data/locales/l10n/lv.yml +215 -0
  115. data/locales/l10n/mk.yml +170 -0
  116. data/locales/l10n/mn.yml +205 -0
  117. data/locales/l10n/nb.yml +207 -0
  118. data/locales/l10n/nl.yml +199 -0
  119. data/locales/l10n/nn.yml +160 -0
  120. data/locales/l10n/pl.yml +221 -0
  121. data/locales/l10n/pt-BR.yml +207 -0
  122. data/locales/l10n/pt-PT.yml +207 -0
  123. data/locales/l10n/quotes.yml +24 -0
  124. data/locales/l10n/rm.yml +182 -0
  125. data/locales/l10n/ro.yml +199 -0
  126. data/locales/l10n/ru.yml +257 -0
  127. data/locales/l10n/sk.yml +213 -0
  128. data/locales/l10n/sl.yml +210 -0
  129. data/locales/l10n/sr-Latn.yml +170 -0
  130. data/locales/l10n/sr.yml +170 -0
  131. data/locales/l10n/sv-SE.yml +199 -0
  132. data/locales/l10n/sw.yml +197 -0
  133. data/locales/l10n/th.yml +173 -0
  134. data/locales/l10n/tl.yml +229 -0
  135. data/locales/l10n/tr.yml +199 -0
  136. data/locales/l10n/uk.yml +257 -0
  137. data/locales/l10n/vi.yml +201 -0
  138. data/locales/l10n/wo.yml +205 -0
  139. data/locales/l10n/zh-CN.yml +199 -0
  140. data/locales/l10n/zh-TW.yml +199 -0
  141. data/template/Gemfile.erb +14 -4
  142. data/template/README +16 -0
  143. data/template/config.yml.erb +42 -38
  144. data/test/fixtures/config_001_simple.yml +2 -0
  145. data/test/fixtures/config_002_l10n.yml +5 -0
  146. data/test/fixtures/pages/invalid-page.markdown +1 -0
  147. data/test/fixtures/pages/multilingual-page.markdown +20 -0
  148. data/test/fixtures/pages/section/subpage.markdown +5 -0
  149. data/test/fixtures/pages/simple-page.markdown +7 -0
  150. data/test/fixtures/posts/2012-07-02-invalid-post.markdown +1 -0
  151. data/test/fixtures/posts/2012-07-02-simple.markdown +7 -0
  152. data/test/fixtures/posts/2012-07-03-full-metadata.markdown +8 -0
  153. data/test/fixtures/posts/2012-07-03-multilingual-full-metadata.markdown +20 -0
  154. data/test/fixtures/theme/test/layouts/default.html.erb +1 -0
  155. data/test/fixtures/theme/test/views/page.html.erb +1 -0
  156. data/test/fixtures/theme/test/views/post.html.erb +1 -0
  157. data/test/minitest_helper.rb +14 -0
  158. data/test/test_config.rb +33 -0
  159. data/test/test_content.rb +30 -0
  160. data/test/test_metadata.rb +83 -0
  161. data/test/test_page.rb +81 -0
  162. data/test/test_post.rb +123 -0
  163. data/test/test_storage.rb +23 -0
  164. data/test/test_storage_file.rb +32 -0
  165. data/test/test_theme.rb +45 -0
  166. data/vendor/assets/images/favicon.png +0 -0
  167. data/vendor/assets/images/grey.gif +0 -0
  168. data/vendor/assets/javascripts/jquery.alula.js.coffee +16 -0
  169. data/vendor/{javascripts → assets/javascripts}/jquery.js +0 -0
  170. data/vendor/assets/javascripts/jquery.lazyload.js +210 -0
  171. data/vendor/assets/javascripts/lazyload.js.coffee +15 -0
  172. data/vendor/layouts/feed.xml.builder +19 -0
  173. data/vendor/layouts/sitemap.xml.builder +10 -0
  174. data/vendor/views/feed_post.html.haml +1 -0
  175. metadata +529 -50
  176. data/lib/alula.rb +0 -5
  177. data/lib/alula/assethelper.rb +0 -75
  178. data/lib/alula/plugins.rb +0 -23
  179. data/lib/alula/plugins/assets.rb +0 -82
  180. data/lib/alula/plugins/pagination.rb +0 -121
  181. data/lib/alula/rake_tasks.rb +0 -42
  182. data/lib/alula/tasks.rb +0 -2
@@ -0,0 +1,46 @@
1
+ require 'alula/storages/filestorage'
2
+
3
+ module Alula
4
+ class Storage
5
+ attr_reader :options
6
+ attr_reader :outputted
7
+
8
+ def self.load(opts = {})
9
+ site = opts[:site]
10
+
11
+ # Get storage class
12
+ # puts "--> #{site.config.storage}"
13
+ type = site.config.storage.keys.last
14
+ cls_name = type[0].upcase + type[1..-1] + "Storage"
15
+ if self.const_defined?(cls_name)
16
+ cls = self.const_get(cls_name)
17
+ return cls.new(site.config.storage[type], opts)
18
+ else
19
+ return nil
20
+ end
21
+ end
22
+
23
+ def initialize(options, opts = {})
24
+ @options = options
25
+ @site = opts[:site]
26
+
27
+ @outputted = []
28
+ end
29
+
30
+ def post(name)
31
+ self.posts[name]
32
+ end
33
+
34
+ def page(name)
35
+ self.pages[name]
36
+ end
37
+
38
+ def custom(name)
39
+ if name.kind_of?(Regexp)
40
+ self.customs.select{|key, item| key[name]}
41
+ else
42
+ self.customs[name]
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ require 'alula/storages/item'
2
+
3
+ module Alula
4
+ class Storage::FileItem < Storage::Item
5
+ def initialize(opts)
6
+ super
7
+
8
+ @file = opts.delete(:file)
9
+ end
10
+
11
+ def exists?
12
+ ::File.file?(@file)
13
+ end
14
+
15
+ def extension
16
+ ::File.extname(@file)[1..-1]
17
+ end
18
+
19
+ def filepath
20
+ @file
21
+ end
22
+
23
+ def has_payload?
24
+ ::File.read(@file, 3) == "---"
25
+ end
26
+
27
+ def size
28
+ ::File.size(@file)
29
+ end
30
+
31
+ def mtime
32
+ ::File.mtime(@file)
33
+ end
34
+
35
+ def read
36
+ ::File.read(@file)
37
+ end
38
+
39
+ def open
40
+ ::File.open(@file)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,96 @@
1
+ # require 'alula/storage'
2
+ require 'alula/storages/file_item'
3
+
4
+ module Alula
5
+ class Storage::FileStorage < Storage
6
+ def initialize(options, opts)
7
+ super
8
+
9
+ # Check we have given directories
10
+ %w{content_path posts_path pages_path attachments_path}.each do |dir|
11
+ raise "Directory #{options[dir]} for #{dir} does not exists!" unless ::File.directory?(options[dir])
12
+ end
13
+ end
14
+
15
+ # List all posts
16
+ def posts
17
+ @posts ||= _list_all_in(self.options["posts_path"])
18
+ end
19
+
20
+ def pages
21
+ @pages ||= _list_all_in(self.options["pages_path"])
22
+ end
23
+
24
+ def attachments
25
+ @attachments ||= _list_all_in(self.options["attachments_path"])
26
+ end
27
+
28
+ def customs
29
+ @customs ||= _list_all_in(self.options["custom_path"])
30
+ end
31
+
32
+ def statics
33
+ @statics ||= _list_all_in(self.options["static_path"])
34
+ end
35
+
36
+ def path(type, *appendum)
37
+ dirname = case type
38
+ when :public
39
+ File.join(self.options["public_path"])
40
+ when :custom
41
+ File.join(self.options["custom_path"])
42
+ when :assets
43
+ File.join(self.options["public_path"], "assets")
44
+ when :cache
45
+ File.join(self.options["cache_path"])
46
+ end
47
+
48
+ dirname = File.join(dirname, appendum) if appendum
49
+
50
+ FileUtils.mkdir_p dirname unless File.directory?(dirname)
51
+
52
+ dirname
53
+ end
54
+
55
+ #
56
+ def prepare(preserve = false)
57
+ if !preserve
58
+ FileUtils.rm_rf self.options["public_path"]
59
+ end
60
+
61
+ FileUtils.mkdir_p self.options["public_path"]
62
+ end
63
+
64
+ def output_public(path, &blk)
65
+ fname = output(:public, path, &blk)
66
+
67
+ # Mark saved file
68
+ @outputted << fname
69
+ end
70
+
71
+ def output(path, file, &blk)
72
+ path = path(path, File.dirname(file))
73
+
74
+ fname = ::File.join(path, File.basename(file))
75
+ dirname = ::File.dirname(fname)
76
+ FileUtils.mkdir_p dirname unless ::File.directory?(dirname)
77
+
78
+ ::File.open(fname, "w") do |io|
79
+ io.puts yield io
80
+ end
81
+
82
+ fname
83
+ end
84
+
85
+ private
86
+ def _list_all_in(path)
87
+ items = {}
88
+ Dir[::File.join(path, "**", "*")].each do |item|
89
+ next unless ::File.file?(item)
90
+ name = item.gsub("#{path}/", '')
91
+ items[name] = FileItem.new(name: name, file: item, storage: self)
92
+ end
93
+ items
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,12 @@
1
+ module Alula
2
+ class Storage
3
+ class Item
4
+ attr_reader :name
5
+
6
+ def initialize(opts = {})
7
+ @name = opts.delete(:name)
8
+ @site = opts.delete(:site)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module Alula
2
+ class CommonLogger
3
+ # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
4
+ # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
5
+ # %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
6
+ FORMAT = %{[%s] %s %s\n}
7
+
8
+ def initialize(app, logger=nil)
9
+ @app = app
10
+ @logger = logger
11
+ end
12
+
13
+ def call(env)
14
+ status, header, body = @app.call(env)
15
+ header = Rack::Utils::HeaderHash.new(header)
16
+ body = Rack::BodyProxy.new(body) { log(env, status, header) }
17
+ [status, header, body]
18
+ end
19
+
20
+ private
21
+
22
+ def log(env, status, header)
23
+ logger = @logger || env['rack.errors']
24
+ logger.write FORMAT % [
25
+ env["REMOTE_ADDR"],
26
+ env["REQUEST_METHOD"],
27
+ Rack::Utils.unescape(env["PATH_INFO"])]
28
+ end
29
+ end
30
+ end
@@ -1,24 +1,81 @@
1
+ require 'alula/theme/layout'
2
+
1
3
  module Alula
2
4
  class Theme
3
- def self.register(path)
4
- @@themepaths ||= []
5
- @@themepaths << path
5
+ attr_reader :site
6
+ attr_reader :theme
7
+ attr_reader :path
8
+ attr_reader :layouts
9
+ attr_reader :context
10
+
11
+ def self.register(theme, path)
12
+ @@themes ||= {}
13
+ @@themes[theme.to_s] = ::File.join(path, theme.to_s)
14
+ end
15
+
16
+ def self.load(opts)
17
+ return nil unless self.class_variable_defined?(:@@themes)
18
+ site = opts[:site]
19
+
20
+ theme_name = site.config.theme
21
+ return self.new(theme_name, opts) if @@themes.has_key?(theme_name)
22
+
23
+ return nil
24
+ end
25
+
26
+ def initialize(theme, opts)
27
+ @site = opts.delete(:site)
28
+ @theme = theme
29
+ @path = @@themes[theme]
30
+
31
+ @context = @site.context
32
+
33
+ @layouts = {}
34
+ @views = {}
6
35
  end
7
36
 
8
- def self.find_theme(themename)
9
- themepath = nil
10
- @@themepaths ||= []
11
- @@themepaths.each do |path|
12
- if File.directory?(File.join(path, themename))
13
- themepath = path
37
+ def searchpath(type, name)
38
+ [
39
+ # Theme path
40
+ ::File.join(self.path, type, "#{name}.*"),
41
+
42
+ # Alula vendor path
43
+ ::File.join(::File.dirname(__FILE__), "..", "..", "vendor", type, "#{name}.*")
44
+ ]
45
+ end
46
+
47
+ def layout(name)
48
+ @layouts[name] ||= begin
49
+ # Find our layout name
50
+ file = Dir[*self.searchpath("layouts", name)].first
51
+ if file
52
+ Layout.new(theme: self, name: name, file: file)
53
+ else
54
+ raise "Cannot find layout #{name}"
14
55
  end
15
56
  end
16
-
17
- themepath
18
57
  end
19
58
 
20
- def self.paths
21
- @@themepaths
59
+ def view(name)
60
+ @views[name] ||= begin
61
+ # Find our layout name
62
+ # file = Dir[::File.join(self.path, "views", "#{name}.*")].first
63
+ file = Dir[*self.searchpath("views", name)].first
64
+ if file
65
+ View.new(theme: self, name: name, file: file)
66
+ else
67
+ raise "Cannot find view #{name}"
68
+ end
69
+ end
70
+ end
71
+
72
+ def options(file)
73
+ options = case File.extname(file)[1..-1]
74
+ when "haml"
75
+ { :format => :html5 }
76
+ else
77
+ {}
78
+ end
22
79
  end
23
80
  end
24
81
  end
@@ -0,0 +1,56 @@
1
+ require 'alula/theme/view'
2
+ require 'tilt'
3
+ require 'sass' # As suggested by tilt
4
+
5
+ module Alula
6
+ class Theme
7
+ class Layout
8
+ attr_reader :theme
9
+ attr_reader :name
10
+ attr_reader :context
11
+
12
+ def initialize(opts)
13
+ @theme = opts.delete(:theme)
14
+ @name = opts.delete(:name)
15
+ @file = opts.delete(:file)
16
+
17
+ @views = {}
18
+
19
+ @context = @theme.context
20
+
21
+ @template = Tilt.new(@file, nil, @theme.options(@file))
22
+ end
23
+
24
+ def view(name)
25
+ @views[name] ||= begin
26
+ # Find our layout name
27
+ file = Dir[::File.join(self.theme.path, "views", "#{name}.*")].first
28
+ if file
29
+ View.new(layout: self, name: name, file: file)
30
+ end
31
+ end
32
+ end
33
+
34
+ def render(content, &blk)
35
+ _old_values = {}
36
+
37
+ # Set up context, make sure we don't change anything
38
+ begin
39
+ content.each do |key, value|
40
+ _old_values[key] = self.context[key]
41
+ self.context[key] = value
42
+ end
43
+
44
+ # Render using our layout template
45
+ @template.render(self.context, &blk)
46
+
47
+ ensure
48
+ _old_values.each do |key, value|
49
+ self.context[key] = value
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,43 @@
1
+ require 'tilt'
2
+
3
+ module Alula
4
+ class Theme
5
+ class View
6
+ attr_reader :theme
7
+ attr_reader :layout
8
+ attr_reader :context
9
+
10
+ def initialize(opts)
11
+ @theme = opts.delete(:theme)
12
+ @name = opts.delete(:name)
13
+ @file = opts.delete(:file)
14
+
15
+ # Shortcuts...
16
+ @context = @theme.context
17
+
18
+ # Load our template
19
+ @template = Tilt.new(@file, nil, @theme.options(@file))
20
+ end
21
+
22
+ def render(content, &blk)
23
+ _old_values = {}
24
+
25
+ # Set up context, make sure we don't change anything
26
+ begin
27
+ content.each do |key, value|
28
+ _old_values[key] = self.context[key]
29
+ self.context[key] = value
30
+ end
31
+
32
+ # Render using our template
33
+ @template.render(self.context, &blk)
34
+
35
+ ensure
36
+ _old_values.each do |key, value|
37
+ self.context[key] = value
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module Alula
2
2
  VERSION = File.read(File.join(File.dirname(__FILE__), %w{.. .. VERSION})).strip
3
- end
3
+ end
@@ -0,0 +1,9 @@
1
+ en:
2
+ recent_posts: Recent Posts
3
+ paginate:
4
+ title: Page %{page}
5
+ older_posts: Older
6
+ newer_posts: Newer
7
+ post:
8
+ previous: Previous Post
9
+ next: Next Post
@@ -0,0 +1,10 @@
1
+ fi:
2
+ recent_posts: Viimeisimmät kirjoitukset
3
+ paginate:
4
+ title: Sivu %{page}
5
+ older_posts: Vanhemmat
6
+ newer_posts: Uudemmat
7
+ post:
8
+ previous: Edellinen kirjoitus
9
+ next: Seuraava kirjoitus
10
+