summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2012-08-24 21:12:36 -0700
committerelijah <elijah@riseup.net>2012-08-24 21:12:36 -0700
commit627f0488e5bd3c31359fc9e78acffbfea4a86a8b (patch)
treef7b14733e314cf82d5fa3e18cbe9d98c2ffe5c7c /lib
parentb774dea07f97b078fa17e5dcbf901d1c83fed0d6 (diff)
committed website v. 0.1.0
Diffstat (limited to 'lib')
-rw-r--r--lib/assets/.gitkeep0
-rw-r--r--lib/config.rb9
-rw-r--r--lib/http_accept_language.rb9
-rw-r--r--lib/http_accept_language/parser.rb104
-rw-r--r--lib/menu.rb78
-rw-r--r--lib/property_set.rb158
-rw-r--r--lib/static_page.rb156
-rw-r--r--lib/tasks/.gitkeep0
8 files changed, 514 insertions, 0 deletions
diff --git a/lib/assets/.gitkeep b/lib/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/assets/.gitkeep
diff --git a/lib/config.rb b/lib/config.rb
new file mode 100644
index 0000000..a579631
--- /dev/null
+++ b/lib/config.rb
@@ -0,0 +1,9 @@
+#
+# Here go any application configuration
+#
+
+SITE_TITLE = "LEAP"
+
+PAGE_DIRECTORY = File.expand_path('../../app/views/pages', __FILE__)
+
+PAGINATION_SIZE = 20
diff --git a/lib/http_accept_language.rb b/lib/http_accept_language.rb
new file mode 100644
index 0000000..87c6ecc
--- /dev/null
+++ b/lib/http_accept_language.rb
@@ -0,0 +1,9 @@
+require 'http_accept_language/parser'
+
+module HttpAcceptLanguage
+
+ def self.compatible_language_from(header, languages)
+ Parser.new(header).compatible_language_from(languages)
+ end
+
+end
diff --git a/lib/http_accept_language/parser.rb b/lib/http_accept_language/parser.rb
new file mode 100644
index 0000000..0aad1a2
--- /dev/null
+++ b/lib/http_accept_language/parser.rb
@@ -0,0 +1,104 @@
+module HttpAcceptLanguage
+
+ class Parser
+
+ attr_accessor :header
+
+ def initialize(header)
+ @header = header
+ end
+
+ # Returns a sorted array based on user preference in HTTP_ACCEPT_LANGUAGE.
+ # Browsers send this HTTP header, so don't think this is holy.
+ #
+ # Example:
+ #
+ # request.user_preferred_languages
+ # # => [ 'nl-NL', 'nl-BE', 'nl', 'en-US', 'en' ]
+ #
+ def user_preferred_languages
+ @user_preferred_languages ||= header.gsub(/\s+/, '').split(/,/).collect do |l|
+ l += ';q=1.0' unless l =~ /;q=\d+\.\d+$/
+ l.split(';q=')
+ end.sort do |x,y|
+ raise "Not correctly formatted" unless x.first =~ /^[a-z\-0-9]+$/i
+ y.last.to_f <=> x.last.to_f
+ end.collect do |l|
+ l.first.downcase.gsub(/-[a-z0-9]+$/i) { |x| x.upcase }
+ end
+ rescue # Just rescue anything if the browser messed up badly.
+ []
+ end
+
+ # Sets the user languages preference, overiding the browser
+ #
+ def user_preferred_languages=(languages)
+ @user_preferred_languages = languages
+ end
+
+ # Finds the locale specifically requested by the browser.
+ #
+ # Example:
+ #
+ # request.preferred_language_from I18n.available_locales
+ # # => 'nl'
+ #
+ def preferred_language_from(array)
+ (user_preferred_languages & array.collect { |i| i.to_s }).first
+ end
+
+ # Returns the first of the user_preferred_languages that is compatible
+ # with the available locales. Ignores region.
+ #
+ # Example:
+ #
+ # request.compatible_language_from I18n.available_locales
+ #
+ def compatible_language_from(available_languages)
+ user_preferred_languages.map do |x| #en-US
+ available_languages.find do |y| # en
+ y = y.to_s
+ x == y || x.split('-', 2).first == y.split('-', 2).first
+ end
+ end.compact.first
+ end
+
+ # Returns a supplied list of available locals without any extra application info
+ # that may be attached to the locale for storage in the application.
+ #
+ # Example:
+ # [ja_JP-x1, en-US-x4, en_UK-x5, fr-FR-x3] => [ja-JP, en-US, en-UK, fr-FR]
+ #
+ def sanitize_available_locales(available_languages)
+ available_languages.map do |avail|
+ split_locale = avail.split(/[_-]/)
+
+ split_locale.map do |e|
+ e unless e.match(/x|[0-9*]/)
+ end.compact.join("-")
+ end
+ end
+
+ # Returns the first of the user preferred languages that is
+ # also found in available languages. Finds best fit by matching on
+ # primary language first and secondarily on region. If no matching region is
+ # found, return the first language in the group matching that primary language.
+ #
+ # Example:
+ #
+ # request.language_region_compatible(available_languages)
+ #
+ def language_region_compatible_from(available_languages)
+ available_languages = sanitize_available_locales(available_languages)
+ user_preferred_languages.map do |x| #en-US
+ lang_group = available_languages.select do |y| # en
+ y = y.to_s
+ x.split('-', 2).first == y.split('-', 2).first
+ end
+ lang_group.find{|l| l == x} || lang_group.first #en-US, en-UK
+ end.compact.first
+ end
+
+ end
+
+end
diff --git a/lib/menu.rb b/lib/menu.rb
new file mode 100644
index 0000000..71690a4
--- /dev/null
+++ b/lib/menu.rb
@@ -0,0 +1,78 @@
+class Menu < Array
+ attr_accessor :parent
+
+ #
+ # class methods
+ #
+
+ #
+ # load the menu.txt file, recursively, and build the in-memory menu array
+ #
+ def self.load(menu_file_path)
+ @menu = Menu.new
+ File.open(menu_file_path) do |file|
+ append_menu_item(@menu, file)
+ end
+ end
+
+ def self.menu
+ @menu || Menu.new
+ end
+
+ def self.create(elements=[], parent=nil)
+ menu = Menu[elements]
+ menu.parent = parent
+ return menu
+ end
+
+ #
+ # public methods
+ #
+
+ def submenu(item_name=nil)
+ if item_name
+ submenu = detect {|item| item[0] == item_name} || Menu.new
+ else
+ submenu = self
+ end
+ return submenu[1..-1] # strip of first element
+ end
+
+ def name
+ first
+ end
+
+ def path
+ @path ||= begin
+ if parent == nil
+ []
+ else
+ parent.path + [name]
+ end
+ end
+ end
+
+ private
+
+ def self.append_menu_item(menu, file)
+ begin
+ item = file.readline
+ rescue EOFError
+ # do nothing
+ else
+ if item !~ /^\s*#/
+ depth = item.scan(" ").size
+ sub_menu = sub_menu_for_depth(menu, depth)
+ sub_menu << Menu.create(item.strip, sub_menu)
+ end
+ append_menu_item(menu, file)
+ end
+ end
+
+ def self.sub_menu_for_depth(menu, depth)
+ sub_menu = menu
+ depth.times { sub_menu = sub_menu[-1] }
+ sub_menu
+ end
+
+end \ No newline at end of file
diff --git a/lib/property_set.rb b/lib/property_set.rb
new file mode 100644
index 0000000..c315a13
--- /dev/null
+++ b/lib/property_set.rb
@@ -0,0 +1,158 @@
+#
+# holds the set or properties defined for each static page.
+# property sets are organized by locale.
+#
+# e.g.
+#
+# setting the property (in en.haml):
+#
+# - @title = 'hi'
+#
+# getting the property
+#
+# page.props.title
+#
+
+require 'i18n'
+require 'time'
+require 'rubygems'
+require 'haml'
+require 'RedCloth'
+
+class PropertySet
+
+ DEFAULT_LOCALE = 'en'
+
+ #
+ # a simple class to pass through all member variables as attributes.
+ # when the template for a page is evaluated, all the member variabled defined in that template
+ # are loaded as member variables of the AttrObject instance.
+ #
+ class AttrObject
+ def initialize(property_set, locale)
+ @_ps = property_set
+ @_locale = locale
+ #code.gsub!(/^((?!^\-\ \@).)*$/, '') # remove any lines not starting with '- @'
+ #code.gsub!(/^- /m, '') # remove '-'
+ #instance_eval(code)
+ #instance_variables.grep(/_at$/).each do |time_variable|
+ # instance_variable_set(time_variable, Time.parse(instance_variable_get(time_variable)))
+ #end
+ end
+ def method_missing(method)
+ get(method)
+ end
+ def textile(str)
+ RedCloth.new(str).to_html
+ end
+ def get(var_name)
+ value = instance_variable_get("@#{var_name}")
+ if value.nil?
+ if @_locale != DEFAULT_LOCALE
+ # try value from default locale
+ @_ps.get_var(var_name)
+ else
+ # try inherited value
+ @_ps.get_inherited_var(var_name, @_locale)
+ end
+ else
+ value
+ end
+ end
+ def set(var_name, value)
+ instance_variable_set("@#{var_name}", value)
+ end
+ end
+
+ def initialize(page=nil)
+ @page = page
+ @locales = {}
+ end
+
+
+ #
+ # maybe something like this in the future:
+ #
+ #contr = PagesController.new()
+ #contr.response = ActionController::Response.new()
+ #scope = ActionView::Base.new(["#{RAILS_ROOT}/app/views/pages","#{RAILS_ROOT}/app/views"], {}, contr)
+ #scope.template_format = 'html'
+ #Haml::Engine.new(value, :format => :html5).render(scope)
+ #
+
+ #
+ # evaluate the template_string, and load the variables defined into an AttrObject.
+ #
+ def eval(locale, template_string)
+ attrs = AttrObject.new(self, locale)
+ body = nil
+ begin
+ body = Haml::Engine.new(template_string, :format => :html5).render(attrs) # template is evaluated in scope of attrs
+ rescue Exception => exc
+ # eat exceptions
+ end
+ attrs.instance_variable_set('@body', body)
+ attrs.instance_variables.grep(/_at$/).each do |time_variable|
+ attrs.instance_variable_set(time_variable, Time.parse(attrs.instance_variable_get(time_variable)))
+ end
+ @locales[locale] = attrs
+ end
+
+ #
+ # allows property_set.propname shortcut, assumes default locale
+ #
+ def method_missing(method)
+ get_var(method)
+ end
+
+ def locale(l)
+ @locales[l.to_s] || @locales[DEFAULT_LOCALE]
+ end
+
+ def get_var(var_name, locale=I18n.locale)
+ attrs = locale(locale)
+ if attrs
+ attrs.get(var_name)
+ else
+ nil
+ end
+ end
+
+ #
+ # tries to get the value of an inherited variable
+ #
+ def get_inherited_var(var_name, locale=I18n.locale)
+ if @page && @page.parent && @page.parent.props
+ @page.parent.props.get_var(var_name, locale)
+ end
+ end
+end
+
+#
+# a simple little test.
+#
+if ARGV.grep('--test').any?
+ text_en = "
+- @title = 'hi'
+- @author = 'you'
+- @created_at = 'Sun Aug 12 18:32:20 PDT 2012'
+- ignored = 1
+this is the body"
+
+ text_es = "
+- @title = 'hola'
+- @author = 'tu'
+- @heading = textile 'h1. hi'
+"
+
+ ps = PropertySet.new
+ ps.eval('en', text_en)
+ ps.eval('es', text_es)
+
+ p ps.title == 'hi'
+ p ps.locale(:es).title == 'hola'
+ p ps.locale(:es).created_at == Time.parse('Sun Aug 12 18:32:20 PDT 2012')
+ p ps.ignored == nil
+ p ps.locale(:es).heading == "<h1>hi</h1>"
+ p ps.body == "this is the body\n"
+end
diff --git a/lib/static_page.rb b/lib/static_page.rb
new file mode 100644
index 0000000..12d4948
--- /dev/null
+++ b/lib/static_page.rb
@@ -0,0 +1,156 @@
+require 'lib/property_set'
+require 'i18n'
+require 'pathname'
+
+class StaticPage
+
+ class PageArray < Array
+ def limit(num)
+ PageArray.new(self[0..(num-1)])
+ end
+ def order_by(attr, locale=I18n.locale)
+ array = sort do |a,b|
+ a_prop = a.props.locale(locale).send(attr)
+ b_prop = b.props.locale(locale).send(attr)
+ if a_prop.nil? && b_prop.nil?
+ 0
+ elsif a_prop.nil?
+ 1
+ elsif b_prop.nil?
+ -1
+ else
+ a_prop <=> b_prop
+ end
+ end
+ array.delete_if do |page|
+ page.props.locale(locale).send(attr).nil?
+ end
+ end
+ end
+
+ attr_accessor :path, :children, :name, :props, :parent
+
+ def self.find(filter)
+ if filter =~ /\//
+ path = filter.split('/').map{|segment| segment.gsub(/[^0-9a-z_-]/, '')}
+ page = @@pages[path.join('/')]
+ if page
+ return page
+ else
+ return @@pages[path.last]
+ end
+ else
+ @@pages[filter]
+ end
+ end
+
+ def self.all
+ @@pages_array
+ end
+
+ def self.load(directory)
+ @@pages = {}
+ @@page_array = PageArray.new
+ @@root_directory = directory
+ @@relative_root_directory = relative_to_rails_view_root(directory)
+ scan_directory(directory) do |page|
+ @@pages[page.name] ||= page
+ @@pages[page.path.join('/')] = page
+ @@page_array << page
+ end
+ end
+
+ def initialize(parent, name)
+ @children = []
+ @name = name
+ if parent
+ @parent = parent
+ @parent.add_child(self)
+ @path = [@parent.path, @name].flatten.compact
+ @props = load_properties(file_path)
+ else
+ @path = []
+ end
+ end
+
+ def add_child(page)
+ @children << page
+ end
+
+ def all_children
+ PageArray.new(child_tree.flatten.compact)
+ end
+
+ #
+ # e.g. /home/user/dev/leap-public-site/app/views/pages/about-us/contact
+ #
+ def file_path
+ "#{@@root_directory}/#{@path.join('/')}"
+ end
+
+ #
+ # e.g. pages/about-us/contact/en
+ #
+ def template_path(locale=I18n.locale)
+ "#{@@relative_root_directory}/#{@path.join('/')}/#{locale}"
+ end
+
+ def inspect
+ "<'#{@path.join('/')}' #{children.inspect}>"
+ end
+
+ def title
+ begin
+ I18n.t!('pages.' + @name, :raise => true)
+ rescue I18n::MissingTranslationData
+ props.title
+ end
+ end
+
+ protected
+
+ def child_tree
+ [self, children.collect{|child| child.child_tree}]
+ end
+
+ private
+
+ def self.scan_directory(directory, parent=nil, &block)
+ parent ||= StaticPage.new(nil, 'root')
+ Dir.chdir directory do
+ Dir.glob("*").each do |child_dir|
+ next unless File.directory?(child_dir)
+ page = StaticPage.new(parent, child_dir)
+ yield page
+ scan_directory(child_dir, page, &block)
+ end
+ end
+ end
+
+ def self.relative_to_rails_view_root(absolute_path)
+ if Rails.root
+ absolute = Pathname.new(absolute_path)
+ rails_view_root = Pathname.new(Rails.root + 'app/views')
+ absolute.relative_path_from(rails_view_root).to_s
+ end
+ end
+
+ def load_properties(file_path)
+ props = PropertySet.new(self)
+ Dir.glob(file_path + '/*.haml') do |content_file_path|
+ locale = File.basename(content_file_path).sub(File.extname(content_file_path),'')
+ #variable_header = ""
+ #p content_file_path
+ #File.open(content_file_path) do |f|
+ # while (line = f.gets) =~ /^- @/
+ # variable_header << line
+ # end
+ #end
+ props.eval(locale, File.read(content_file_path))
+ end
+ return props
+ end
+
+end
+
+
diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/tasks/.gitkeep