amber 0.3.8 → 0.3.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d45088b2c65fd274e44926886b8a70f0a645f73
4
- data.tar.gz: 305ef95bcb2143c71331cfe7e702b97ee9f987f1
3
+ metadata.gz: 5f07ec2e5c2a86cec442c924598f935a40955a32
4
+ data.tar.gz: 4eaecfe55678b175942014c5e17f6e90381021b6
5
5
  SHA512:
6
- metadata.gz: 5b4fc64f2b1f57cafa02c21d2392448e64de89648a9ebe54ae06b26b43febcbf5a5b663804c3b7ff3932c5553077ae82be017490ed922ba8571e5c0aaa6ba706
7
- data.tar.gz: a6ab0937bad9f67492940655bfbcf1e04e9b79c48e5a9ec5761686b25a39d1c2165d0b54d19f76cf470e6e14e8b55edc30b61a446f4ca22ea8a38f49fd423f44
6
+ metadata.gz: efa8c04a618b8ba9052c6b4f0f1387bb750e20a3544e6afe79668cee9de9278c44168c2ce00fe70fc14c8dc4a3faebdb6a5b069e059cd913adc37373f8ade543
7
+ data.tar.gz: 78c14db10c74f733f0cc1899715ccbf771a3bd9b29aebdf84af8d24bd0025845ced2b0df3adfa5c7237e63619defe0932eae0280561f66f1a0051f8d8c21d3b7
@@ -21,6 +21,10 @@ module Amber
21
21
  # Possible page suffixes. Only files with these suffixes are treated as pages
22
22
  PAGE_SUFFIXES = %w(haml md markdown text textile rst html html.haml)
23
23
 
24
+ # Possible variable file suffixes. Only files with these suffixesare treated
25
+ # as variable files.
26
+ VAR_SUFFIXES = %w(json yaml yml)
27
+
24
28
  DEFAULT_HOST = '127.0.0.1'
25
29
  DEFAULT_PORT = '8000'
26
30
 
@@ -56,7 +60,8 @@ require 'amber/render/layout'
56
60
  require 'amber/render/view'
57
61
  require 'amber/render/template'
58
62
  require 'amber/render/asset'
59
- require 'amber/render/autolink'
60
- require 'amber/render/bracketlink'
61
63
  require 'amber/render/table_of_contents'
62
64
  require 'amber/render/apache'
65
+ require 'amber/render/filter/autolink'
66
+ require 'amber/render/filter/bracketlink'
67
+ require 'amber/render/filter/variables'
@@ -13,7 +13,7 @@ module Amber
13
13
  new_dir = options[:arg]
14
14
  mkdir(new_dir, nil)
15
15
  mkdir('amber', new_dir)
16
- touch('amber/config.rb', new_dir)
16
+ copy_template_file('config.rb', 'amber', new_dir)
17
17
  touch('amber/menu.txt', new_dir)
18
18
  mkdir('amber/layouts', new_dir)
19
19
  mkdir('amber/locales', new_dir)
@@ -40,8 +40,8 @@ module Amber
40
40
  site = Site.new(@root)
41
41
  site.continue_on_error = false
42
42
  site.load_pages
43
- FileUtils.mkdir_p(site.dest_dir) unless File.exists?(site.dest_dir)
44
- gitkeep = File.exists?(File.join(site.dest_dir, '.gitkeep'))
43
+ FileUtils.mkdir_p(site.dest_dir) unless File.exist?(site.dest_dir)
44
+ gitkeep = File.exist?(File.join(site.dest_dir, '.gitkeep'))
45
45
  temp_render = File.join(File.dirname(site.dest_dir), 'public-tmp')
46
46
  temp_old_pages = File.join(File.dirname(site.dest_dir), 'remove-me')
47
47
  site.with_destination(temp_render) do
@@ -58,8 +58,8 @@ module Amber
58
58
  end
59
59
  ensure
60
60
  # cleanup if something goes wrong.
61
- FileUtils.rm_r(temp_render) if temp_render && File.exists?(temp_render)
62
- FileUtils.rm_r(temp_old_pages) if temp_old_pages && File.exists?(temp_old_pages)
61
+ FileUtils.rm_r(temp_render) if temp_render && File.exist?(temp_render)
62
+ FileUtils.rm_r(temp_old_pages) if temp_old_pages && File.exist?(temp_old_pages)
63
63
  end
64
64
 
65
65
  def server(options)
@@ -100,8 +100,8 @@ module Amber
100
100
  path = dir
101
101
  print_path = dir
102
102
  end
103
- unless Dir.exists?(path)
104
- if File.exists?(path)
103
+ unless Dir.exist?(path)
104
+ if File.exist?(path)
105
105
  puts "Could not make directory `#{print_path}`. File already exists."
106
106
  exit(1)
107
107
  end
@@ -112,11 +112,22 @@ module Amber
112
112
 
113
113
  def touch(file, context)
114
114
  path = File.join(context, file)
115
- unless File.exists?(path)
115
+ unless File.exist?(path)
116
116
  FileUtils.touch(path)
117
117
  puts "* Creating `#{File.basename(context)}/#{file}`"
118
118
  end
119
119
  end
120
120
 
121
+ def copy_template_file(template_file, destination, context)
122
+ template_file_path = File.dirname(__FILE__) + "/templates/#{template_file}"
123
+ copy(template_file_path, destination, context)
124
+ end
125
+
126
+ def copy(source, destination, context)
127
+ destination_path = File.join(context, destination)
128
+ FileUtils.copy(source, destination_path)
129
+ puts "* Creating `#{File.basename(context)}/#{destination}/#{File.basename(source)}`"
130
+ end
131
+
121
132
  end
122
- end
133
+ end
@@ -8,7 +8,7 @@ module Amber
8
8
  template = Tilt::ERBTemplate.new(template_path("htaccess.erb"))
9
9
 
10
10
  tail_content = nil
11
- if File.exists?(src_htaccess_file)
11
+ if File.exist?(src_htaccess_file)
12
12
  tail_content = File.read(src_htaccess_file)
13
13
  end
14
14
  File.open(dst_htaccess_file, 'w', :encoding => 'UTF-8') do |f|
@@ -19,10 +19,10 @@ module Amber
19
19
  }
20
20
 
21
21
  def self.render(src_file, dst_file)
22
- unless Dir.exists?(File.dirname(dst_file))
22
+ unless Dir.exist?(File.dirname(dst_file))
23
23
  FileUtils.mkdir_p(File.dirname(dst_file))
24
24
  end
25
- File.unlink(dst_file) if File.exists?(dst_file)
25
+ File.unlink(dst_file) if File.exist?(dst_file)
26
26
  src_ext = File.extname(src_file)
27
27
  renderer = RENDER_MAP[src_ext]
28
28
  if renderer
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+ # adapted from https://github.com/tenderlove/rails_autolink
3
+ # MIT license
4
+
5
+ module Amber
6
+ module Render
7
+ module Filter
8
+ module Autolink
9
+
10
+ def self.run(text)
11
+ auto_link_email_addresses(auto_link_urls(text))
12
+ end
13
+
14
+ private
15
+
16
+ AUTO_LINK_RE = %r{
17
+ (?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs|file):)// | www\. )
18
+ [^\s<\u00A0]+
19
+ }ix
20
+
21
+ # regexps for determining context, used high-volume
22
+ AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
23
+
24
+ AUTO_EMAIL_LOCAL_RE = /[\w.!#\$%&'*\/=?^`{|}~+-]/
25
+ AUTO_EMAIL_RE = /[\w.!#\$%+-]\.?#{AUTO_EMAIL_LOCAL_RE}*@[\w-]+(?:\.[\w-]+)+/
26
+
27
+ BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
28
+
29
+ WORD_PATTERN = RUBY_VERSION < '1.9' ? '\w' : '\p{Word}'
30
+
31
+ # Turns all urls into clickable links. If a block is given, each url
32
+ # is yielded and the result is used as the link text.
33
+ def self.auto_link_urls(text)
34
+ text.gsub(AUTO_LINK_RE) do
35
+ scheme, href = $1, $&
36
+ punctuation = []
37
+
38
+ if auto_linked?($`, $')
39
+ # do not change string; URL is already linked
40
+ href
41
+ else
42
+ # don't include trailing punctuation character as part of the URL
43
+ while href.sub!(/[^#{WORD_PATTERN}\/-]$/, '')
44
+ punctuation.push $&
45
+ if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
46
+ href << punctuation.pop
47
+ break
48
+ end
49
+ end
50
+
51
+ #link_text = block_given?? yield(href) : href
52
+ link_text = href.sub(/^#{scheme}\/\//,'')
53
+ href = 'http://' + href unless scheme
54
+ %(<a href="#{href}">#{link_text}</a>) + punctuation.reverse.join('')
55
+ end
56
+ end
57
+ end
58
+
59
+ # Turns all email addresses into clickable links.
60
+ def self.auto_link_email_addresses(text)
61
+ text.gsub(AUTO_EMAIL_RE) do
62
+ text = $&
63
+
64
+ if auto_linked?($`, $')
65
+ text
66
+ else
67
+ #display_text = (block_given?) ? yield(text) : text
68
+ #display_text = text
69
+ text.gsub!('@', '&#064').gsub!('.', '&#046;')
70
+ %(<a href="mailto:#{text}">#{text}</a>)
71
+ end
72
+ end
73
+ end
74
+
75
+ # Detects already linked context or position in the middle of a tag
76
+ def self.auto_linked?(left, right)
77
+ (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
78
+ (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # bracket links are links in the form [[label => target]] or [[page-name]]
5
+ #
6
+
7
+ module Amber
8
+ module Render
9
+ module Filter
10
+ module Bracketlink
11
+
12
+ # linking using double square brackets
13
+ BRACKET_LINK_RE = /
14
+ \[\[ # start [[
15
+ ([^\[\]]+) # $text : one or more characters that are not [ or ] ($1)
16
+ \]\] # end ]]
17
+ /x
18
+
19
+ def self.run(text, &block)
20
+ text.gsub(BRACKET_LINK_RE) do |m|
21
+ link_text = $~[1].strip
22
+ if link_text =~ /^.+\s*[-=]>\s*.+$/
23
+ # link_text == "from -> to"
24
+ from, to = link_text.split(/\s*[-=]>\s*/)[0..1]
25
+ from = "" unless from.instance_of? String # \ sanity check for
26
+ to = "" unless from.instance_of? String # / badly formed links
27
+ else
28
+ # link_text == "to" (ie, no link label)
29
+ from = nil
30
+ to = link_text
31
+ end
32
+ yield(from, to)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # bracket links are links in the form [[label => target]] or [[page-name]]
5
+ #
6
+
7
+ module Amber
8
+ module Render
9
+ module Filter
10
+ module Variables
11
+
12
+ # variable expansion uses {{ }}
13
+ VARIABLES_RE = /
14
+ \{\{ # start {{
15
+ ([^\{\}]+) # $text : one or more characters that are not { or } ($1)
16
+ \}\} # end }}
17
+ /x
18
+
19
+ def self.run(text, &block)
20
+ text.gsub(VARIABLES_RE) do |m|
21
+ variable_name = $~[1].strip
22
+ yield(variable_name)
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -6,7 +6,7 @@ module Amber
6
6
  limit = options[:limit] || @site.pagination_size
7
7
  order = options[:order] || :posted_at
8
8
  direction = options[:direction] || :desc
9
- partial = options[:partial]
9
+ #partial = options[:partial]
10
10
  if options[:path]
11
11
  @site.find_page(options[:path])
12
12
  else
@@ -108,7 +108,7 @@ module Amber
108
108
  levels_max = options[:levels] || 1
109
109
  level = options.delete(:level) || 1
110
110
  heading = options.delete(:heading) || 2
111
- locale = @locals[:locale]
111
+ #locale = @locals[:locale]
112
112
  menu = submenu_for_page(page)
113
113
  if menu && menu.children.any?
114
114
  children = menu.children
@@ -27,6 +27,7 @@ module Amber::Render
27
27
  @heading_anchors = {}
28
28
  @options = options
29
29
  @options[:tag] ||= 'ol'
30
+ @parsed = nil
30
31
  end
31
32
 
32
33
  def to_html
@@ -125,7 +125,10 @@ module Amber
125
125
 
126
126
  def render_haml(file_path, view)
127
127
  template = Tilt::HamlTemplate.new(file_path, {:format => :html5, :default_encoding => 'UTF-8'})
128
- add_bracket_links(view, template.render(view, view.locals))
128
+ html = template.render(view, view.locals)
129
+ html = add_variables(view, html)
130
+ html = add_bracket_links(view, html)
131
+ return html
129
132
  rescue Haml::Error => ex
130
133
  msg = "Line #{ex.line + 1} of file `#{file_path}`: #{ex.to_s}"
131
134
  Amber::logger.error(msg)
@@ -133,34 +136,46 @@ module Amber
133
136
  end
134
137
 
135
138
  def render_textile(view, content)
139
+ content = add_variables(view, content)
136
140
  content = add_bracket_links(view, content)
137
- Autolink.auto_link(RedCloth.new(content).to_html)
141
+ return Filter::Autolink.run(RedCloth.new(content).to_html)
138
142
  end
139
143
 
140
144
  def render_markdown(view, content)
145
+ content = add_variables(view, content)
141
146
  content = add_bracket_links(view, content)
142
- RDiscount.new(content, :smart, :autolink).to_html
147
+ return RDiscount.new(content, :smart, :autolink).to_html
143
148
  end
144
149
 
145
150
  def render_raw(view, content)
146
- add_bracket_links(view, content)
151
+ content = add_variables(view, content)
152
+ content = add_bracket_links(view, content)
153
+ return content
147
154
  end
148
155
 
149
156
  def render_none(view, content)
150
- content
157
+ return content
151
158
  end
152
159
 
153
160
  def add_bracket_links(view, content)
154
- content = Bracketlink.bracket_link(content) do |from, to|
161
+ content = Filter::Bracketlink.run(content) do |from, to|
155
162
  view.link({from => to})
156
163
  end
157
- content
164
+ return content
165
+ end
166
+
167
+ def add_variables(view, content)
168
+ locale = view.locals[:locale]
169
+ content = Filter::Variables.run(content) do |var_name|
170
+ view.page.var(var_name, locale) || var_name
171
+ end
172
+ return content
158
173
  end
159
174
 
160
175
  def type_from_file(file_path)
161
176
  suffix = File.extname(file_path)
162
177
  if suffix
163
- suffix.sub! /^\./, ''
178
+ suffix.sub!(/^\./, '')
164
179
  suffix = suffix.to_sym
165
180
  end
166
181
  suffix
@@ -57,6 +57,7 @@ module Amber
57
57
  @page = options[:page] if options[:page]
58
58
  render_toc = should_render_toc?(locale, options, @page)
59
59
  template = pick_template(locale, options)
60
+ return unless template
60
61
  if toc_only
61
62
  template.render(self, :mode => :toc, :href_base => options[:href_base])
62
63
  else
@@ -90,32 +91,33 @@ module Amber
90
91
  # search possible paths for the file to be rendered.
91
92
  # called only from parse_render_options()
92
93
  #
93
- def find_file(path, site, page, locale)
94
- return path if File.exists?(path)
95
- search = [
96
- path,
97
- "#{site.pages_dir}/#{path}",
98
- "#{page.file_path}/#{path}",
99
- "#{File.dirname(page.file_path)}/#{path}",
100
- "#{site.config_dir}/#{path}"
94
+ def find_file(search_path, site, page, locale)
95
+ return search_path if File.exist?(search_path)
96
+ searches = [
97
+ search_path,
98
+ "#{site.pages_dir}/#{search_path}",
99
+ "#{page.file_path}/#{search_path}",
100
+ "#{File.dirname(page.file_path)}/#{search_path}",
101
+ "#{site.config_dir}/#{search_path}"
101
102
  ]
102
103
  # attempt to find a file with preferred locale
103
- search.each do |path|
104
- return path if File.exists?(path)
104
+ searches.each do |path|
105
+ return path if File.exist?(path)
105
106
  Dir["#{path}.#{locale}.#{StaticPage::PAGE_SUFFIXES_GLOB}"].each do |path_with_locale|
106
- return path_with_locale if File.exists?(path_with_locale)
107
+ return path_with_locale if File.exist?(path_with_locale)
107
108
  end
108
109
  Dir["#{path}.#{StaticPage::PAGE_SUFFIXES_GLOB}"].each do |path_with_suffix|
109
- return path_with_suffix if File.exists?(path_with_suffix)
110
+ return path_with_suffix if File.exist?(path_with_suffix)
110
111
  end
111
112
  end
112
113
  # attempt to find a file with default locale
113
- search.each do |path|
114
- Dir["#{path}.#{I18n.default_locale}.#{StaticPage::PAGE_SUFFIXES_GLOB}"].each do |path_with_locale|
115
- return path_with_locale if File.exists?(path_with_locale)
114
+ searches.each do |path2|
115
+ Dir["#{path2}.#{I18n.default_locale}.#{StaticPage::PAGE_SUFFIXES_GLOB}"].each do |path_with_locale|
116
+ return path_with_locale if File.exist?(path_with_locale)
116
117
  end
117
118
  end
118
- raise MissingTemplate.new(path)
119
+ Amber.logger.error("No such path `#{path2}` from `#{page.content_file(locale)}`.")
120
+ return nil
119
121
  end
120
122
 
121
123
  def partialize(path)
@@ -181,6 +183,8 @@ module Amber
181
183
  Template.new(file: options[:partial], partial: true)
182
184
  elsif options[:text]
183
185
  Template.new(content: options[:text], type: (options[:type] || :text))
186
+ else
187
+ nil
184
188
  end
185
189
  end
186
190
 
@@ -138,11 +138,11 @@ module Amber
138
138
  @server.site.render
139
139
  page.render_to_file(dst_dir, :force => true)
140
140
  file = page.destination_file(dst_dir, locale)
141
- if File.exists?(file)
141
+ if File.exist?(file)
142
142
  content = File.read(file)
143
143
  else
144
144
  file = page.destination_file(dst_dir, I18n.default_locale)
145
- if File.exists?(file)
145
+ if File.exist?(file)
146
146
  content = File.read(file)
147
147
  else
148
148
  view = Render::View.new(page, @server.site)
@@ -162,7 +162,7 @@ module Amber
162
162
  base_path = path.sub(RENDERABLE_ASSET_RE, '')
163
163
  Amber::Render::Asset::SOURCE_MAP[dest_suffix].each do |source_suffix|
164
164
  source_file_path = File.join(src_dir, base_path + source_suffix)
165
- if File.exists?(source_file_path)
165
+ if File.exist?(source_file_path)
166
166
  return source_file_path
167
167
  end
168
168
  end
@@ -81,8 +81,8 @@ module Amber
81
81
  # Which would match "/services/chat/security" but not "/services/security"
82
82
  #
83
83
  def find_pages(filter)
84
- filter = filter.downcase
85
- if filter =~ /\//
84
+ filter = filter.downcase
85
+ if filter =~ /\//
86
86
  path = filter.split('/').map{|segment| segment.gsub(/[^0-9a-z_-]/, '')}
87
87
  path_str = path.join('/')
88
88
  if (page = @pages_by_path[path_str])
@@ -152,9 +152,9 @@ module Amber
152
152
  @root
153
153
  else
154
154
  name = File.basename(config.path)
155
- page = StaticPage.new(find_parent(config.path), name, config.pages_dir, config.path_prefix)
156
- add_page(page)
157
- page
155
+ sub_root = StaticPage.new(find_parent(config.path), name, config.pages_dir, config.path_prefix)
156
+ add_page(sub_root)
157
+ sub_root
158
158
  end
159
159
  end
160
160
  base_page.config = config
@@ -56,6 +56,7 @@ module Amber
56
56
  #
57
57
  def initialize(site, root_dir, options={})
58
58
  @children = []
59
+ @path_prefix = nil
59
60
  @site = site
60
61
  @root_dir = File.expand_path(find_in_directory_tree('amber', 'config.rb', root_dir))
61
62
  if @root_dir == '/'
@@ -119,7 +120,7 @@ module Amber
119
120
 
120
121
  def config_path(file)
121
122
  path = File.join(@config_dir, file)
122
- if File.exists?(path)
123
+ if File.exist?(path)
123
124
  path
124
125
  else
125
126
  nil
@@ -134,7 +135,7 @@ module Amber
134
135
  search_dir = directory_tree || Dir.pwd
135
136
  while search_dir != "/"
136
137
  Dir.foreach(search_dir) do |f|
137
- if f == target_dir_name && File.exists?(File.join(search_dir, f,target_file_name))
138
+ if f == target_dir_name && File.exist?(File.join(search_dir, f,target_file_name))
138
139
  return search_dir
139
140
  end
140
141
  end
@@ -0,0 +1,95 @@
1
+ #
2
+ # responsible for loading all the pages of the site.
3
+ #
4
+
5
+ WORK IN PROGRESS, FACTOR OUT FROM SITE
6
+
7
+ module Amber
8
+ class SiteLoader
9
+
10
+ #
11
+ # page_paths
12
+ # pages_by_name
13
+ # pages_by_path
14
+ # pages_by_locale_path
15
+ # root
16
+ # dir_list
17
+ #
18
+ def self.load(config)
19
+ config.reset_timestamp
20
+
21
+ # create base_page
22
+ base_page = begin
23
+ if config.path.nil?
24
+ @root = StaticPage.new(nil, 'root', config.pages_dir)
25
+ add_page(@root)
26
+ @root
27
+ else
28
+ name = File.basename(config.path)
29
+ page = StaticPage.new(find_parent(config.path), name, config.pages_dir, config.path_prefix)
30
+ add_page(page)
31
+ page
32
+ end
33
+ end
34
+ base_page.config = config
35
+
36
+ # load menu and locals
37
+ I18n.load_path += Dir[File.join(config.locales_dir, '/*.{rb,yml,yaml}')] if config.locales_dir
38
+
39
+ # add the full directory tree
40
+ base_page.scan_directory_tree do |page, asset_dir|
41
+ add_page(page) if page
42
+ @dir_list << asset_dir if asset_dir
43
+ end
44
+ @page_paths += @pages_by_path.keys
45
+
46
+ # recursively add sub-sites
47
+ config.children.each do |sub_config|
48
+ add_configuration(sub_config)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def self.find_parent(path)
55
+ so_far = []
56
+ path.split('/').compact.each do |path_segment|
57
+ so_far << path_segment
58
+ if page = @pages_by_path[so_far.join('/')]
59
+ return page
60
+ end
61
+ end
62
+ return @root
63
+ end
64
+
65
+ #
66
+ # registers a page with the site, indexing the page path in our various hashes
67
+ #
68
+ def add_page(page)
69
+ @pages_by_name[page.name] = page
70
+ @pages_by_path[page.path.join('/')] = page
71
+ add_aliases(I18n.default_locale, page, @pages_by_path)
72
+ page.locales.each do |locale|
73
+ next if locale == I18n.default_locale
74
+ add_aliases(locale, page, @pages_by_locale_path[locale])
75
+ end
76
+ @page_list << page
77
+ end
78
+
79
+ #
80
+ # registers a page's aliases with the site
81
+ #
82
+ def add_aliases(locale, page, path_hash)
83
+ page.aliases(locale).each do |alias_path|
84
+ alias_path_str = alias_path.join('/')
85
+ if path_hash[alias_path_str]
86
+ 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})."
87
+ else
88
+ path_hash[alias_path_str] = page
89
+ end
90
+ end
91
+ end
92
+
93
+
94
+ end
95
+ end
@@ -112,6 +112,14 @@ module Amber
112
112
  @props.prop(*args)
113
113
  end
114
114
 
115
+ def vars
116
+ @vars ||= load_variables
117
+ end
118
+
119
+ def var(name, locale=I18n.locale)
120
+ (vars[locale] || vars[I18n.default_locale] || {})[name.to_s]
121
+ end
122
+
115
123
  #
116
124
  # Returns array of locale symbols for all locales with properties set
117
125
  # Note: there might be a content for a locale that does not show up in this array,
@@ -121,6 +129,10 @@ module Amber
121
129
  @props.locales
122
130
  end
123
131
 
132
+ def path_str
133
+ self.path.join('/')
134
+ end
135
+
124
136
  #
125
137
  # returns an array of normalized aliases based on the :alias property
126
138
  # defined for a page.
@@ -132,9 +144,9 @@ module Amber
132
144
  def aliases(locale=I18n.default_locale)
133
145
  @aliases ||= begin
134
146
  aliases_hash = Hash.new([])
135
- @props.locales.each do |locale|
136
- aliases = @props.prop_without_inheritance(locale, :alias)
137
- aliases_hash[locale] = begin
147
+ @props.locales.each do |l|
148
+ aliases = @props.prop_without_inheritance(l, :alias)
149
+ aliases_hash[l] = begin
138
150
  if aliases.nil?
139
151
  []
140
152
  else
@@ -5,6 +5,8 @@
5
5
  require 'i18n'
6
6
  require 'pathname'
7
7
  require 'fileutils'
8
+ require 'json'
9
+ require 'yaml'
8
10
 
9
11
  module Amber
10
12
  class StaticPage
@@ -106,11 +108,19 @@ module Amber
106
108
  PAGE_SUFFIXES_RE = /(?<suffix>#{Amber::PAGE_SUFFIXES.join('|')})/
107
109
  PAGE_SUFFIXES_GLOB = "{#{Amber::PAGE_SUFFIXES.join(',')}}"
108
110
 
111
+ # e.g. json, yaml
112
+ VAR_SUFFIXES_RE = /(?<suffix>#{Amber::VAR_SUFFIXES.join('|')})/
113
+ VAR_SUFFIXES_GLOB = "{#{Amber::VAR_SUFFIXES.join(',')}}"
114
+
109
115
  # e.g. en.haml or es.md or index.pt.text
110
116
  LOCALE_FILE_MATCH_RE = /^(index\.)?#{LOCALES_RE}\.#{PAGE_SUFFIXES_RE}$/
111
117
  LOCALE_FILE_MATCH_GLOB = "{index.,}#{LOCALES_GLOB}.#{PAGE_SUFFIXES_GLOB}"
112
118
 
119
+ VAR_FILE_MATCH_RE = /^(index\.)?#{LOCALES_RE}\.#{VAR_SUFFIXES_RE}$/
120
+ VAR_FILE_MATCH_GLOB = "{index.,}#{LOCALES_GLOB}.#{VAR_SUFFIXES_GLOB}"
121
+
113
122
  SIMPLE_FILE_MATCH_RE = lambda {|name| /^(#{Regexp.escape(name)})(\.#{LOCALES_RE})?\.#{PAGE_SUFFIXES_RE}$/ }
123
+ SIMPLE_VAR_MATCH_RE = lambda {|name| /^(#{Regexp.escape(name)})(\.#{LOCALES_RE})?\.#{VAR_SUFFIXES_RE}$/ }
114
124
 
115
125
  private
116
126
 
@@ -198,11 +208,13 @@ module Amber
198
208
  if @simple_page
199
209
  []
200
210
  else
201
- assets = {}
202
211
  Dir.foreach(@file_path).collect { |file|
203
- if file && file !~ /\.#{PAGE_SUFFIXES_RE}$/
204
- file unless File.directory?(File.join(@file_path, file))
205
- end
212
+ is_asset = \
213
+ file &&
214
+ file !~ /\.#{PAGE_SUFFIXES_RE}$/ &&
215
+ file !~ /^#{VAR_FILE_MATCH_RE}$/ &&
216
+ !File.directory?(File.join(@file_path, file))
217
+ file if is_asset
206
218
  }.compact
207
219
  end
208
220
  end
@@ -223,24 +235,22 @@ module Amber
223
235
  #
224
236
  # (with or without leading hypen works)
225
237
  #
226
- # this text is extracted and evaluated as ruby to set properties.
238
+ # This text is extracted and evaluated as ruby to set properties.
239
+ #
240
+ # The first paragraph is loaded into the property "excerpt".
227
241
  #
228
242
  def load_properties
229
243
  props = PageProperties.new(self)
230
244
  content_files.each do |locale, content_file|
231
- if File.extname(content_file) == '.haml'
245
+ if type_from_path(content_file) == :haml
232
246
  props.eval(File.read(content_file, :encoding => 'UTF-8'), locale)
233
247
  else
234
- headers = []
235
- File.open(content_file, :encoding => 'UTF-8') do |f|
236
- while (line = f.gets) =~ /^(- |)@\w/
237
- if line !~ /^-/
238
- line = '- ' + line
239
- end
240
- headers << line
241
- end
248
+ headers, excerpt = parse_headers(content_file)
249
+ props.eval(headers, locale)
250
+ if !excerpt.empty?
251
+ props.set_prop(locale, "excerpt", excerpt)
242
252
  end
243
- props.eval(headers.join("\n"), locale)
253
+ props.set_prop(locale, "content_type", type_from_path(content_file))
244
254
  end
245
255
  cleanup_properties(props, locale)
246
256
  end
@@ -256,10 +266,123 @@ module Amber
256
266
  end
257
267
  end
258
268
 
269
+ #
270
+ # parses a content_file's property headers and tries to extract the
271
+ # first paragraph.
272
+ #
273
+ def parse_headers(content_file)
274
+ headers = []
275
+ para1 = []
276
+ para2 = []
277
+ file_type = type_from_path(content_file)
278
+
279
+ File.open(content_file, :encoding => 'UTF-8') do |f|
280
+ while (line = f.gets) =~ /^(- |)@\w/
281
+ if line !~ /^-/
282
+ line = '- ' + line
283
+ end
284
+ headers << line
285
+ end
286
+ # eat empty lines
287
+ while line = f.gets
288
+ break unless line =~ /^\s*$/
289
+ end
290
+ # grab first two paragraphs
291
+ para1 << line
292
+ while line = f.gets
293
+ break if line =~ /^\s*$/
294
+ para1 << line
295
+ end
296
+ while line = f.gets
297
+ break if line =~ /^\s*$/
298
+ para2 << line
299
+ end
300
+ end
301
+
302
+ headers = headers.join
303
+ para1 = para1.join
304
+ para2 = para2.join
305
+ excerpt = ""
306
+
307
+ # pick the first non-heading paragraph.
308
+ # this is stupid, and chokes on nested headings.
309
+ # but is also cheap and fast :)
310
+ if file_type == :textile
311
+ if para1 =~ /^h[1-5]\. /
312
+ excerpt = para2
313
+ else
314
+ excerpt = para1
315
+ end
316
+ elsif file_type == :markdown
317
+ if para1 =~ /^#+ / || para1 =~ /^(===+|---+)\s*$/m
318
+ excerpt = para2
319
+ else
320
+ excerpt = para1
321
+ end
322
+ end
323
+ return [headers, excerpt]
324
+ end
325
+
326
+ ##
327
+ ## VARIABLES
328
+ ## Variables are associated with a page, but unlike properties they are not
329
+ ## inheritable. Variables are defined in a separate file.
330
+ ##
331
+ def variable_files
332
+ if @simple_page
333
+ directory = File.dirname(@file_path)
334
+ regexp = SIMPLE_VAR_MATCH_RE.call(@name)
335
+ else
336
+ directory = @file_path
337
+ regexp = VAR_FILE_MATCH_RE
338
+ end
339
+ hsh = {}
340
+ Dir.foreach(directory) do |file|
341
+ if file && match = regexp.match(file)
342
+ locale = match['locale'] || I18n.default_locale
343
+ hsh[locale.to_sym] = File.join(directory, file)
344
+ end
345
+ end
346
+ hsh
347
+ end
348
+
349
+ def load_variables
350
+ vars = {}
351
+ variable_files.each do |locale, var_file|
352
+ begin
353
+ if var_file =~ /\.ya?ml$/
354
+ vars[locale] = YAML.load_file(var_file)
355
+ elsif var_file =~ /\.json$/
356
+ vars[locale] = JSON.parse(File.read(var_file))
357
+ end
358
+ rescue StandardError => exc
359
+ Amber.logger.error('ERROR: could not load file #{var_file}: ' + exc.to_s)
360
+ end
361
+ end
362
+ return vars
363
+ end
364
+
365
+ def type_from_path(path)
366
+ case File.extname(path)
367
+ when ".text", ".textile"
368
+ :textile
369
+ when ".md", ".markdown"
370
+ :markdown
371
+ when ".haml"
372
+ :haml
373
+ when ".html"
374
+ :html
375
+ when ".erb"
376
+ :erb
377
+ else
378
+ :unknown
379
+ end
380
+ end
381
+
259
382
  # RAILS
260
383
  #def is_haml_template?(locale)
261
384
  # content_file(locale) =~ /\.haml$/
262
- # #@suffix == '.haml' || File.exists?(self.absolute_template_path(locale) + '.haml')
385
+ # #@suffix == '.haml' || File.exist?(self.absolute_template_path(locale) + '.haml')
263
386
  #end
264
387
 
265
388
  end
@@ -39,11 +39,11 @@ module Amber
39
39
  #
40
40
  def get(property_name, inheritable_only=false)
41
41
  if inheritable_only || @this.nil?
42
- instance_variable_get("@#{property_name}")
42
+ safe_instance_get("@#{property_name}")
43
43
  else
44
44
  value = @this.get(property_name)
45
45
  if value.nil?
46
- value = instance_variable_get("@#{property_name}")
46
+ value = safe_instance_get("@#{property_name}")
47
47
  end
48
48
  value
49
49
  end
@@ -68,11 +68,22 @@ module Amber
68
68
  def to_s
69
69
  "<" + instance_variables.map{|v| "#{v}=#{instance_variable_get(v)}"}.join(', ') + ">"
70
70
  end
71
+
72
+ private
73
+
74
+ def safe_instance_get(prop_name)
75
+ if !instance_variable_defined?(prop_name)
76
+ instance_variable_set(prop_name, nil)
77
+ end
78
+ instance_variable_get(prop_name)
79
+ end
71
80
  end
72
81
 
73
82
  class ThisPropertySet < PropertySet
74
83
  def initialize
84
+ @this = nil
75
85
  end
76
86
  end
87
+
77
88
  end
78
89
  end
@@ -122,7 +122,7 @@ module Amber
122
122
  content_file = content_file(file_locale)
123
123
  next unless content_file
124
124
  dest = destination_file(dest_dir, file_locale)
125
- unless Dir.exists?(File.dirname(dest))
125
+ unless Dir.exist?(File.dirname(dest))
126
126
  FileUtils.mkdir_p(File.dirname(dest))
127
127
  end
128
128
  if options[:force] || !File.exist?(dest) || File.mtime(content_file) > File.mtime(dest)
@@ -0,0 +1,4 @@
1
+ @title = "Your site's title"
2
+ @default_locale = :en
3
+ @locales = [:en, :fr]
4
+ @short_paths = true
@@ -1,5 +1,5 @@
1
1
  module Amber
2
2
  unless defined?(Amber::VERSION)
3
- VERSION = '0.3.8'
3
+ VERSION = '0.3.11'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elijah Sparrow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-12 00:00:00.000000000 Z
11
+ date: 2016-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -142,8 +142,9 @@ files:
142
142
  - lib/amber/page_array.rb
143
143
  - lib/amber/render/apache.rb
144
144
  - lib/amber/render/asset.rb
145
- - lib/amber/render/autolink.rb
146
- - lib/amber/render/bracketlink.rb
145
+ - lib/amber/render/filter/autolink.rb
146
+ - lib/amber/render/filter/bracketlink.rb
147
+ - lib/amber/render/filter/variables.rb
147
148
  - lib/amber/render/helpers/blog_helper.rb
148
149
  - lib/amber/render/helpers/date_helper.rb
149
150
  - lib/amber/render/helpers/haml_helper.rb
@@ -157,6 +158,7 @@ files:
157
158
  - lib/amber/server.rb
158
159
  - lib/amber/site.rb
159
160
  - lib/amber/site_configuration.rb
161
+ - lib/amber/site_loader.rb
160
162
  - lib/amber/static_page.rb
161
163
  - lib/amber/static_page/filesystem.rb
162
164
  - lib/amber/static_page/page_properties.rb
@@ -164,6 +166,7 @@ files:
164
166
  - lib/amber/static_page/render.rb
165
167
  - lib/amber/templates/apache_config.erb
166
168
  - lib/amber/templates/apache_config_with_prefix.erb
169
+ - lib/amber/templates/config.rb
167
170
  - lib/amber/templates/htaccess.erb
168
171
  - lib/amber/version.rb
169
172
  - locales/rails-i18n/af.yml
@@ -291,3 +294,4 @@ signing_key:
291
294
  specification_version: 4
292
295
  summary: Static website generator
293
296
  test_files: []
297
+ has_rdoc:
@@ -1,78 +0,0 @@
1
- # encoding: utf-8
2
- # adapted from https://github.com/tenderlove/rails_autolink
3
- # MIT license
4
-
5
- module Amber::Render::Autolink
6
-
7
- def self.auto_link(text)
8
- auto_link_email_addresses(auto_link_urls(text))
9
- end
10
-
11
- private
12
-
13
- AUTO_LINK_RE = %r{
14
- (?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs|file):)// | www\. )
15
- [^\s<\u00A0]+
16
- }ix
17
-
18
- # regexps for determining context, used high-volume
19
- AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
20
-
21
- AUTO_EMAIL_LOCAL_RE = /[\w.!#\$%&'*\/=?^`{|}~+-]/
22
- AUTO_EMAIL_RE = /[\w.!#\$%+-]\.?#{AUTO_EMAIL_LOCAL_RE}*@[\w-]+(?:\.[\w-]+)+/
23
-
24
- BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
25
-
26
- WORD_PATTERN = RUBY_VERSION < '1.9' ? '\w' : '\p{Word}'
27
-
28
- # Turns all urls into clickable links. If a block is given, each url
29
- # is yielded and the result is used as the link text.
30
- def self.auto_link_urls(text)
31
- text.gsub(AUTO_LINK_RE) do
32
- scheme, href = $1, $&
33
- punctuation = []
34
-
35
- if auto_linked?($`, $')
36
- # do not change string; URL is already linked
37
- href
38
- else
39
- # don't include trailing punctuation character as part of the URL
40
- while href.sub!(/[^#{WORD_PATTERN}\/-]$/, '')
41
- punctuation.push $&
42
- if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
43
- href << punctuation.pop
44
- break
45
- end
46
- end
47
-
48
- #link_text = block_given?? yield(href) : href
49
- link_text = href.sub(/^#{scheme}\/\//,'')
50
- href = 'http://' + href unless scheme
51
- %(<a href="#{href}">#{link_text}</a>) + punctuation.reverse.join('')
52
- end
53
- end
54
- end
55
-
56
- # Turns all email addresses into clickable links.
57
- def self.auto_link_email_addresses(text)
58
- text.gsub(AUTO_EMAIL_RE) do
59
- text = $&
60
-
61
- if auto_linked?($`, $')
62
- text
63
- else
64
- #display_text = (block_given?) ? yield(text) : text
65
- #display_text = text
66
- text.gsub!('@', '&#064').gsub!('.', '&#046;')
67
- %(<a href="mailto:#{text}">#{text}</a>)
68
- end
69
- end
70
- end
71
-
72
- # Detects already linked context or position in the middle of a tag
73
- def self.auto_linked?(left, right)
74
- (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
75
- (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
76
- end
77
-
78
- end
@@ -1,33 +0,0 @@
1
- # encoding: utf-8
2
-
3
- #
4
- # bracket links are links in the form [[label => target]] or [[page-name]]
5
- #
6
-
7
- module Amber::Render::Bracketlink
8
-
9
- # linking using double square brackets
10
- BRACKET_LINK_RE = /
11
- \[\[ # start [[
12
- ([^\[\]]+) # $text : one or more characters that are not [ or ] ($1)
13
- \]\] # end ]]
14
- /x
15
-
16
- def self.bracket_link(text, &block)
17
- text.gsub(BRACKET_LINK_RE) do |m|
18
- link_text = $~[1].strip
19
- if link_text =~ /^.+\s*[-=]>\s*.+$/
20
- # link_text == "from -> to"
21
- from, to = link_text.split(/\s*[-=]>\s*/)[0..1]
22
- from = "" unless from.instance_of? String # \ sanity check for
23
- to = "" unless from.instance_of? String # / badly formed links
24
- else
25
- # link_text == "to" (ie, no link label)
26
- from = nil
27
- to = link_text
28
- end
29
- yield(from, to)
30
- end
31
- end
32
-
33
- end