amber 0.2.6 → 0.3.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 (129) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +14 -1
  3. data/README.md +88 -19
  4. data/bin/amber +26 -13
  5. data/lib/amber.rb +25 -39
  6. data/lib/amber/cli.rb +25 -1
  7. data/lib/amber/i18n.rb +43 -0
  8. data/lib/amber/render/apache.rb +44 -0
  9. data/lib/amber/render/asset.rb +28 -2
  10. data/lib/amber/render/helpers/blog_helper.rb +35 -0
  11. data/lib/amber/render/helpers/date_helper.rb +14 -0
  12. data/lib/amber/render/helpers/haml_helper.rb +9 -0
  13. data/lib/amber/render/helpers/html_helper.rb +30 -8
  14. data/lib/amber/render/helpers/navigation_helper.rb +31 -32
  15. data/lib/amber/render/layout.rb +2 -1
  16. data/lib/amber/render/template.rb +24 -11
  17. data/lib/amber/render/view.rb +31 -12
  18. data/lib/amber/server.rb +122 -56
  19. data/lib/amber/site.rb +171 -29
  20. data/lib/amber/site_configuration.rb +26 -11
  21. data/lib/amber/static_page.rb +34 -20
  22. data/lib/amber/static_page/filesystem.rb +3 -7
  23. data/lib/amber/static_page/page_properties.rb +7 -0
  24. data/lib/amber/static_page/render.rb +47 -31
  25. data/lib/amber/templates/apache_config.erb +12 -0
  26. data/lib/amber/templates/apache_config_with_prefix.erb +14 -0
  27. data/lib/amber/templates/htaccess.erb +176 -0
  28. data/lib/amber/version.rb +5 -0
  29. data/locales/rails-i18n/af.yml +201 -0
  30. data/locales/rails-i18n/ar.yml +274 -0
  31. data/locales/rails-i18n/az.yml +192 -0
  32. data/locales/rails-i18n/bg.yml +192 -0
  33. data/locales/rails-i18n/bn.yml +175 -0
  34. data/locales/rails-i18n/bs.yml +243 -0
  35. data/locales/rails-i18n/ca.yml +192 -0
  36. data/locales/rails-i18n/cs.yml +210 -0
  37. data/locales/rails-i18n/cy.yml +242 -0
  38. data/locales/rails-i18n/da.yml +198 -0
  39. data/locales/rails-i18n/de-AT.yml +202 -0
  40. data/locales/rails-i18n/de-CH.yml +206 -0
  41. data/locales/rails-i18n/de.yml +202 -0
  42. data/locales/rails-i18n/el.yml +198 -0
  43. data/locales/rails-i18n/en-AU.yml +198 -0
  44. data/locales/rails-i18n/en-CA.yml +207 -0
  45. data/locales/rails-i18n/en-GB.yml +198 -0
  46. data/locales/rails-i18n/en-IE.yml +198 -0
  47. data/locales/rails-i18n/en-IN.yml +198 -0
  48. data/locales/rails-i18n/en-NZ.yml +198 -0
  49. data/locales/rails-i18n/en-US.yml +204 -0
  50. data/locales/rails-i18n/en-ZA.yml +204 -0
  51. data/locales/rails-i18n/en.yml +204 -0
  52. data/locales/rails-i18n/eo.yml +194 -0
  53. data/locales/rails-i18n/es-419.yml +207 -0
  54. data/locales/rails-i18n/es-AR.yml +198 -0
  55. data/locales/rails-i18n/es-CL.yml +192 -0
  56. data/locales/rails-i18n/es-CO.yml +198 -0
  57. data/locales/rails-i18n/es-CR.yml +198 -0
  58. data/locales/rails-i18n/es-EC.yml +204 -0
  59. data/locales/rails-i18n/es-MX.yml +204 -0
  60. data/locales/rails-i18n/es-PA.yml +204 -0
  61. data/locales/rails-i18n/es-PE.yml +177 -0
  62. data/locales/rails-i18n/es-US.yml +198 -0
  63. data/locales/rails-i18n/es-VE.yml +198 -0
  64. data/locales/rails-i18n/es.yml +192 -0
  65. data/locales/rails-i18n/et.yml +192 -0
  66. data/locales/rails-i18n/eu.yml +192 -0
  67. data/locales/rails-i18n/fa.yml +192 -0
  68. data/locales/rails-i18n/fi.yml +192 -0
  69. data/locales/rails-i18n/fr-CA.yml +200 -0
  70. data/locales/rails-i18n/fr-CH.yml +200 -0
  71. data/locales/rails-i18n/fr.yml +214 -0
  72. data/locales/rails-i18n/gl.yml +171 -0
  73. data/locales/rails-i18n/he.yml +194 -0
  74. data/locales/rails-i18n/hi-IN.yml +192 -0
  75. data/locales/rails-i18n/hi.yml +192 -0
  76. data/locales/rails-i18n/hr.yml +236 -0
  77. data/locales/rails-i18n/hu.yml +192 -0
  78. data/locales/rails-i18n/id.yml +193 -0
  79. data/locales/rails-i18n/is.yml +212 -0
  80. data/locales/rails-i18n/iso-639-2/csb.yml +203 -0
  81. data/locales/rails-i18n/iso-639-2/dsb.yml +208 -0
  82. data/locales/rails-i18n/iso-639-2/fur.yml +192 -0
  83. data/locales/rails-i18n/iso-639-2/gsw-CH.yml +196 -0
  84. data/locales/rails-i18n/iso-639-2/hsb.yml +207 -0
  85. data/locales/rails-i18n/iso-639-2/pap-AW.yml +205 -0
  86. data/locales/rails-i18n/iso-639-2/pap-CW.yml +205 -0
  87. data/locales/rails-i18n/iso-639-2/scr.yml +236 -0
  88. data/locales/rails-i18n/it-CH.yml +198 -0
  89. data/locales/rails-i18n/it.yml +204 -0
  90. data/locales/rails-i18n/ja.yml +194 -0
  91. data/locales/rails-i18n/km.yml +54 -0
  92. data/locales/rails-i18n/kn.yml +192 -0
  93. data/locales/rails-i18n/ko.yml +190 -0
  94. data/locales/rails-i18n/lo.yml +227 -0
  95. data/locales/rails-i18n/lt.yml +217 -0
  96. data/locales/rails-i18n/lv.yml +229 -0
  97. data/locales/rails-i18n/mk.yml +198 -0
  98. data/locales/rails-i18n/mn.yml +198 -0
  99. data/locales/rails-i18n/ms.yml +200 -0
  100. data/locales/rails-i18n/nb.yml +205 -0
  101. data/locales/rails-i18n/ne.yml +198 -0
  102. data/locales/rails-i18n/nl.yml +204 -0
  103. data/locales/rails-i18n/nn.yml +201 -0
  104. data/locales/rails-i18n/or.yml +192 -0
  105. data/locales/rails-i18n/pl.yml +236 -0
  106. data/locales/rails-i18n/pt-BR.yml +206 -0
  107. data/locales/rails-i18n/pt.yml +200 -0
  108. data/locales/rails-i18n/rm.yml +223 -0
  109. data/locales/rails-i18n/ro.yml +205 -0
  110. data/locales/rails-i18n/ru.yml +256 -0
  111. data/locales/rails-i18n/sk.yml +206 -0
  112. data/locales/rails-i18n/sl.yml +205 -0
  113. data/locales/rails-i18n/sr.yml +236 -0
  114. data/locales/rails-i18n/sv.yml +192 -0
  115. data/locales/rails-i18n/sw.yml +190 -0
  116. data/locales/rails-i18n/ta.yml +204 -0
  117. data/locales/rails-i18n/th.yml +166 -0
  118. data/locales/rails-i18n/tl.yml +224 -0
  119. data/locales/rails-i18n/tr.yml +204 -0
  120. data/locales/rails-i18n/uk.yml +250 -0
  121. data/locales/rails-i18n/ur.yml +204 -0
  122. data/locales/rails-i18n/uz.yml +250 -0
  123. data/locales/rails-i18n/vi.yml +198 -0
  124. data/locales/rails-i18n/wo.yml +198 -0
  125. data/locales/rails-i18n/zh-CN.yml +203 -0
  126. data/locales/rails-i18n/zh-HK.yml +204 -0
  127. data/locales/rails-i18n/zh-TW.yml +203 -0
  128. data/locales/rails-i18n/zh-YUE.yml +204 -0
  129. metadata +164 -74
@@ -15,8 +15,9 @@ module Amber
15
15
 
16
16
  def initialize(options)
17
17
  @site = options[:site]
18
+ @host = options[:host]
18
19
  @port = options[:port]
19
- @server = WEBrick::HTTPServer.new :Port => @port, :BindAddress => '127.0.0.1', :DocumentRoot => @site.dest_dir
20
+ @server = WEBrick::HTTPServer.new :Port => @port, :BindAddress => @host, :DocumentRoot => @site.dest_dir
20
21
  @server.mount '/', StaticPageServlet, self
21
22
  end
22
23
 
@@ -30,6 +31,9 @@ module Amber
30
31
 
31
32
  class StaticPageServlet < WEBrick::HTTPServlet::FileHandler
32
33
 
34
+ RENDERABLE_ASSET_RE = /(#{Amber::Render::Asset::SOURCE_MAP.keys.join('|')})$/
35
+ ASSET_RE = /\.(jpg|jpeg|png|gif|webm|css|js|ico)$/
36
+
33
37
  def initialize(http_server, amber_server)
34
38
  @logger = http_server.logger
35
39
  @server = amber_server
@@ -37,77 +41,139 @@ module Amber
37
41
  end
38
42
 
39
43
  def do_GET(request, response)
40
- dest_dir = @server.site.dest_dir
41
-
42
- # add local prefix for all paths that don't have a file suffix
43
- if request.path !~ /\.[a-z]{2,4}$/
44
- locale = get_locale(request)
45
- if !locale
46
- location = "http://localhost:#{@server.port}/#{I18n.default_locale}#{request.path.sub(/\/$/,'')}"
47
- @logger.info "Redirect %s ==> %s" % [request.path, location]
48
- response.header['Location'] = location
49
- response.status = 307
50
- return
51
- end
44
+ if path_needs_to_be_prefixed?(request.path)
45
+ redirect_with_prefix(request, response)
46
+ return
52
47
  end
53
48
 
54
- if File.exists?(File.join(dest_dir, request.path))
55
- @logger.info "Serve static file %s" % File.join(dest_dir, request.path)
49
+ path = strip_locale_and_prefix(request.path)
50
+
51
+ if renderable_asset?(path)
52
+ @logger.info "Rendering asset file %s" % asset_source_file(path)
53
+ render_asset(path, request, response)
56
54
  super(request, response)
55
+ elsif static_file_exists?(request.path)
56
+ @logger.info "Serve static file %s" % static_file_path(request.path)
57
+ super(request, response)
58
+ elsif static_file_exists?(path)
59
+ request = request.clone
60
+ request.instance_variable_set(:@path_info, "/"+path)
61
+ @logger.info "Serve static file with locale prefix %s" % static_file_path(path)
62
+ super(request, response)
63
+ elsif path !~ ASSET_RE
64
+ render_page(path, request, response)
57
65
  else
58
- path = strip_locale(request.path)
59
- @server.site.load_pages
60
- page = @server.site.find_page_by_path(path)
61
- if page
62
- @logger.info "Serving Page %s" % page.path.join('/')
63
- response.status = 200
64
- response.content_type = "text/html; charset=utf-8"
65
- # always refresh the page we are fetching
66
- Amber::Render::Layout.reload
67
- @server.site.render
68
- page.render_to_file(dest_dir, :force => true)
69
- file = page.destination_file(dest_dir, locale)
70
- if File.exists?(file)
71
- content = File.read(file)
72
- else
73
- file = page.destination_file(dest_dir, I18n.default_locale)
74
- if File.exists?(file)
75
- content = File.read(file)
76
- else
77
- view = Render::View.new(page, @server.site)
78
- content = view.render(:text => "No file found at #{file}")
79
- end
80
- end
81
- response.body = content
82
- else
83
- request = request.clone
84
- request.instance_variable_set(:@path_info, "/" + strip_locale(request.path_info))
85
- @logger.info "Serve static file %s" % File.join(dest_dir, request.path_info)
86
- super(request, response)
87
- end
66
+ super(request, response)
88
67
  end
89
68
  end
90
- #rescue Exception => exc
91
- # @logger.error exc.to_s
92
- # @logger.error exc.backtrace
93
- # response.status = 500
94
- # response.content_type = 'text/text'
95
- # response.body = exc.to_s + "\n\n\n\n" + exc.backtrace
96
69
 
97
70
  private
98
71
 
99
- def strip_locale(path)
100
- path.sub(/^\/(#{Amber::POSSIBLE_LANGUAGE_CODES.join('|')})(\/|$)/, '').sub(/\/$/, '')
72
+ def strip_locale_and_prefix(path)
73
+ # The path comes to the server as URL escaped codes, that are then
74
+ # converty to ascii. But these codes might be utf-8 characters, so we force
75
+ # utf-8 encouding to allows non-ascii paths. I am not sure if always forcing
76
+ # will be a problem.
77
+ path = path.force_encoding('utf-8')
78
+ if @server.site.path_prefix
79
+ path = path.sub(%r{^/?#{Regexp.escape(@server.site.path_prefix)}}, '')
80
+ end
81
+ path.sub(%r{^/?(#{Amber::POSSIBLE_LANGUAGE_CODES.join('|')})(/|$)}, '').sub(%r{/$}, '')
101
82
  end
102
83
 
103
- def get_locale(request)
104
- match = /\/(#{Amber::POSSIBLE_LANGUAGE_CODES.join('|')})(\/|$)/.match(request.path)
84
+ def get_locale(path)
85
+ match = /\/(#{Amber::POSSIBLE_LANGUAGE_CODES.join('|')})(\/|$)/.match(path)
105
86
  if match.nil?
106
87
  nil
107
88
  else
108
89
  match[1]
109
90
  end
110
91
  end
111
- end
112
92
 
93
+ def path_needs_to_be_prefixed?(path)
94
+ if @server.site.path_prefix
95
+ path !~ /\.[a-z]{2,4}$/ && (
96
+ path !~ %r{^/?#{Regexp.escape(@server.site.path_prefix)}} ||
97
+ get_locale(path).nil?
98
+ )
99
+ else
100
+ path !~ /\.[a-z]{2,4}$/ && get_locale(path).nil?
101
+ end
102
+ end
103
+
104
+ def redirect_with_prefix(request, response)
105
+ path = request.path.gsub(%r{^/|/$}, '')
106
+ location = ["http://localhost:#{@server.port}", @server.site.path_prefix, I18n.default_locale, path].compact.join('/')
107
+ @logger.info "Redirect %s ==> %s" % [request.path, location]
108
+ response.header['Location'] = location
109
+ response.status = 307
110
+ end
111
+
112
+ def dst_dir
113
+ @server.site.dest_dir
114
+ end
115
+
116
+ def src_dir
117
+ @server.site.pages_dir
118
+ end
119
+
120
+ def static_file_exists?(path)
121
+ File.file?(File.join(dst_dir, path))
122
+ end
123
+
124
+ def static_file_path(path)
125
+ File.join(dst_dir, path)
126
+ end
127
+
128
+ def render_page(path, request, response)
129
+ locale = get_locale(request.path)
130
+ @server.site.load_pages
131
+ page = @server.site.find_page_by_path(path, locale)
132
+ if page
133
+ @logger.info "Serving Page %s" % page.path.join('/')
134
+ response.status = 200
135
+ response.content_type = "text/html; charset=utf-8"
136
+ # always refresh the page we are fetching
137
+ Amber::Render::Layout.reload
138
+ @server.site.render
139
+ page.render_to_file(dst_dir, :force => true)
140
+ file = page.destination_file(dst_dir, locale)
141
+ if File.exists?(file)
142
+ content = File.read(file)
143
+ else
144
+ file = page.destination_file(dst_dir, I18n.default_locale)
145
+ if File.exists?(file)
146
+ content = File.read(file)
147
+ else
148
+ view = Render::View.new(page, @server.site)
149
+ content = view.render(:text => "No file found at #{file}")
150
+ end
151
+ end
152
+ response.body = content
153
+ end
154
+ end
155
+
156
+ def renderable_asset?(path)
157
+ path =~ RENDERABLE_ASSET_RE && asset_source_file(path)
158
+ end
159
+
160
+ def asset_source_file(path)
161
+ dest_suffix = File.extname(path)
162
+ base_path = path.sub(RENDERABLE_ASSET_RE, '')
163
+ Amber::Render::Asset::SOURCE_MAP[dest_suffix].each do |source_suffix|
164
+ source_file_path = File.join(src_dir, base_path + source_suffix)
165
+ if File.exists?(source_file_path)
166
+ return source_file_path
167
+ end
168
+ end
169
+ return nil
170
+ end
171
+
172
+ def render_asset(path, request, response)
173
+ src_file = asset_source_file(path)
174
+ dst_file = [dst_dir, path].join
175
+ Amber::Render::Asset.render(src_file, dst_file)
176
+ end
177
+
178
+ end
113
179
  end
@@ -9,32 +9,39 @@ module Amber
9
9
  attr_accessor :root
10
10
  attr_accessor :continue_on_error
11
11
 
12
- def_delegators :@config, :dest_dir, :locales, :default_locale
12
+ # @config is the primary SiteConfiguration
13
+ def_delegators :@config, :pages_dir, :dest_dir, :locales, :default_locale, :path_prefix
13
14
 
14
15
  def initialize(root_dir)
15
16
  @continue_on_error = true
16
17
  @config = SiteConfiguration.load(self, root_dir)
17
18
  end
18
19
 
20
+ def add_config(config)
21
+ @config.children << config
22
+ end
23
+
19
24
  def load_pages
20
25
  @root = nil
21
- @pages_by_path = {}
22
- @pages_by_name = {}
26
+ @pages_by_path = {} # hash of pages keyed by page path
27
+ @pages_by_name = {} # hash of pages keyed by page name
23
28
  @page_list = PageArray.new
24
- @dir_list = []
25
- @config.mount_points.each do |mp|
26
- add_mount_point(mp)
27
- mp.reset_timestamp
28
- end
29
- end
29
+ @dir_list = [] # an array of non-page directories
30
+ @page_paths = [] # an array of page paths, used for greping through paths.
30
31
 
31
- def reload_pages_if_needed
32
- if @pages_by_path.nil? || @config.pages_changed?
33
- puts "Reloading pages ................."
34
- load_pages
35
- end
32
+ # some paths are specific to only one locale (e.g aliases)
33
+ @pages_by_locale_path = POSSIBLE_LANGUAGES.keys.inject(Hash.new({})) {|h,locale| h[locale] = {}; h}
34
+
35
+ add_configuration(@config)
36
36
  end
37
37
 
38
+ #def reload_pages_if_needed
39
+ # if @pages_by_path.nil? || @config.pages_changed?
40
+ # puts "Reloading pages ................."
41
+ # load_pages
42
+ # end
43
+ #end
44
+
38
45
  def render
39
46
  @page_list.each do |page|
40
47
  page.render_to_file(@config.dest_dir)
@@ -46,6 +53,10 @@ module Amber
46
53
  Render::Asset.render_dir(src, dst)
47
54
  putc '.'; $stdout.flush
48
55
  end
56
+ if @config.short_paths
57
+ render_short_path_symlinks
58
+ end
59
+ Render::Apache.write_htaccess(@config, @config.pages_dir, @config.dest_dir)
49
60
  puts
50
61
  end
51
62
 
@@ -62,6 +73,13 @@ module Amber
62
73
  @config.dest_dir = dest_dir
63
74
  end
64
75
 
76
+ #
77
+ # find pages by a filter.
78
+ # filter is a string composing a path segment.
79
+ # For example:
80
+ # "chat/security"
81
+ # Which would match "/services/chat/security" but not "/services/security"
82
+ #
65
83
  def find_pages(filter)
66
84
  filter = filter.downcase
67
85
  if filter =~ /\//
@@ -89,54 +107,100 @@ module Amber
89
107
  @page_list
90
108
  end
91
109
 
92
- def find_page_by_path(path)
93
- @pages_by_path[path]
110
+ def find_page_by_path(path, locale=I18n.default_locale)
111
+ if locale.is_a? String
112
+ if I18n.locale_available?(locale)
113
+ locale = locale.to_sym
114
+ end
115
+ end
116
+ if path.is_a? Array
117
+ path = path.join('/')
118
+ end
119
+ @pages_by_locale_path[locale][path] || @pages_by_path[path]
94
120
  end
95
121
 
96
122
  def find_page_by_name(name)
97
123
  @pages_by_name[name]
98
124
  end
99
125
 
126
+ #
127
+ # returns the shortest possible path for a page, such that the path doesn't collide with
128
+ # another page or another page's aliases.
129
+ #
130
+ def shortest_path(page)
131
+ path_so_far = []
132
+ page.path.reverse.each do |path_segment|
133
+ path_so_far.push(path_segment)
134
+ path_str = path_so_far.join('/')
135
+ if @pages_by_path[path_str].nil? && short_paths[path_str] == page
136
+ return path_so_far
137
+ end
138
+ end
139
+ return []
140
+ end
141
+
100
142
  private
101
143
 
102
- def add_mount_point(mp)
144
+ def add_configuration(config)
145
+ config.reset_timestamp
146
+
103
147
  # create base_page
104
148
  base_page = begin
105
- if mp.path == '/'
106
- @root = StaticPage.new(nil, 'root', mp.pages_dir)
149
+ if config.path.nil?
150
+ @root = StaticPage.new(nil, 'root', config.pages_dir)
107
151
  add_page(@root)
108
152
  @root
109
153
  else
110
- name = File.basename(mp.path)
111
- page = StaticPage.new(find_parent(mp.path), name, mp.pages_dir)
154
+ name = File.basename(config.path)
155
+ page = StaticPage.new(find_parent(config.path), name, config.pages_dir, config.path_prefix)
112
156
  add_page(page)
113
157
  page
114
158
  end
115
159
  end
116
- base_page.mount_point = mp
160
+ base_page.config = config
117
161
 
118
162
  # load menu and locals
119
- I18n.load_path += Dir[File.join(mp.locales_dir, '/*.{rb,yml,yaml}')] if mp.locales_dir
163
+ I18n.load_path += Dir[File.join(config.locales_dir, '/*.{rb,yml,yaml}')] if config.locales_dir
120
164
 
121
165
  # add the full directory tree
122
166
  base_page.scan_directory_tree do |page, asset_dir|
123
167
  add_page(page) if page
124
168
  @dir_list << asset_dir if asset_dir
125
169
  end
126
- @page_paths = @pages_by_path.keys
170
+ @page_paths += @pages_by_path.keys
171
+
172
+ # recursively add sub-sites
173
+ config.children.each do |sub_config|
174
+ add_configuration(sub_config)
175
+ end
127
176
  end
128
177
 
178
+ #
179
+ # registers a page with the site, indexing the page path in our various hashes
180
+ #
129
181
  def add_page(page)
130
182
  @pages_by_name[page.name] = page
131
183
  @pages_by_path[page.path.join('/')] = page
132
- page.aliases.each do |alias_path|
133
- if @pages_by_path[alias_path]
134
- Amber.logger.warn "WARNING: page `#{page.path.join('/')}` has alias `#{alias_path}`, but this path is already taken"
184
+ add_aliases(I18n.default_locale, page, @pages_by_path)
185
+ page.locales.each do |locale|
186
+ next if locale == I18n.default_locale
187
+ add_aliases(locale, page, @pages_by_locale_path[locale])
188
+ end
189
+ @page_list << page
190
+ end
191
+
192
+ #
193
+ # registers a page's aliases with the site
194
+ #
195
+ def add_aliases(locale, page, path_hash)
196
+ page.aliases(locale).each do |alias_path|
197
+ alias_path_str = alias_path.join('/')
198
+ if path_hash[alias_path_str]
199
+ Amber.logger.warn "WARNING: page `#{page.path.join('/')}` has alias `#{alias_path_str}`, but this path is already taken by `#{path_hash[alias_path_str].path.join('/')}` (locale = #{locale})."
135
200
  else
136
- @pages_by_path[alias_path] = page
201
+ path_hash[alias_path_str] = page
137
202
  end
138
203
  end
139
- @page_list << page
140
204
  end
141
205
 
142
206
  def find_parent(path)
@@ -150,5 +214,83 @@ module Amber
150
214
  return @root
151
215
  end
152
216
 
217
+ #
218
+ # adds symlinks for all possible 'short paths' for every page.
219
+ # this works by:
220
+ # (1) examine all pages in order of longest path depth and assign 'short paths' for each page.
221
+ # (2) examine all short paths in order of shortest path depth and create symlinks
222
+ #
223
+ def render_short_path_symlinks
224
+ short_paths.each do |path, page|
225
+ page.link_page_aliases(@config.dest_dir, [path])
226
+ end
227
+ end
228
+
229
+ #
230
+ # returns a hash containing all the automatically determined shortest paths for every page.
231
+ # the data structure looks like so:
232
+ #
233
+ # {
234
+ # "ddd" => <page 'bbb/ddd'>,
235
+ # "ccc" => <page 'bbb/ccc'>,
236
+ # "red" => <page 'autoalias/red'>,
237
+ # "blue"=> <page 'autoalias/blue'>,
238
+ # "red/blue" => <page 'autoalias/red/blue'>
239
+ # }
240
+ #
241
+ # short_paths does not include the normal paths or normal aliases, just the automatic short path aliases.
242
+ #
243
+ def short_paths
244
+ @short_paths ||= begin
245
+ hash = {}
246
+ pages_in_path_depth_order.each do |record|
247
+ page = record[:page]
248
+ path = record[:path]
249
+ next if path.length == 1
250
+ path_prefix = path.dup
251
+ path.length.times do |depth|
252
+ path_prefix.shift
253
+ path_str = path_prefix.join('/')
254
+ if @pages_by_path[path_str].nil? && hash[path_str].nil?
255
+ hash[path_str] = page
256
+ end
257
+ end
258
+ end
259
+ # debug:
260
+ #hash.each do |path, record|
261
+ # puts "#{record[:page].path.join('/')} => #{record[:path].join('/')}"
262
+ #end
263
+ hash
264
+ end
265
+ end
266
+
267
+ #
268
+ # Returns an array like this:
269
+ #
270
+ # [
271
+ # {:page => <page1>, :path => ['a', 'page1']},
272
+ # {:page => <page2>, :path => ['a','b', 'page2']},
273
+ # ]
274
+ #
275
+ # This array is sorted by the depth of the path (shortest first)
276
+ # Pages will appear multiple times (once for each path, including aliases)
277
+ #
278
+ def pages_in_path_depth_order
279
+ paths = {}
280
+ @page_list.each do |page|
281
+ paths[page.path] ||= page
282
+ locales = page.locales
283
+ locales << I18n.default_locale unless locales.include? I18n.default_locale
284
+ locales.each do |locale|
285
+ page.aliases(locale).each do |alias_path|
286
+ paths[alias_path] ||= page
287
+ end
288
+ end
289
+ end
290
+ paths.collect{|path, page| {page:page, path:path}}.sort{|a,b|
291
+ a[:path].length <=> a[:path].length
292
+ }
293
+ end
294
+
153
295
  end
154
296
  end