first implementation of site loader

arnaud sellenet committed Jun 03, 2014
commit c44d78f3a3c6547c846e68e5ed03bf41cefecc9a
Showing 6 changed files with 306 additions and 10 deletions
locomotive/steam/loaders/yml/pages_loader.rb b/lib/locomotive/steam/loaders/yml/pages_loader.rb +161 -0
@@ @@ -0,0 +1,161 @@
+ module Locomotive
+ module Steam
+ module Loader
+ module Yml
+ class PagesLoader
+ def initialize(path, mapper)
+ @root_path = path
+ @path = File.join(path, 'app', 'views', 'pages')
+ @mapper = mapper
+ end
+
+
+ # Build the tree of pages based on the filesystem structure
+ #
+ # @return [ Hash ] The pages organized as a Hash (using the fullpath as the key)
+ #
+ def load!
+ entity_class = @mapper.collection(:pages).entity
+ repository = @mapper.collection(:pages).repository
+ all.each do |record|
+ page = entity_class.new(record)
+ repository.create page, :en
+
+ end
+ end
+
+ protected
+
+ # Create a ordered list of pages from the Hash
+ #
+ # @return [ Array ] An ordered list of pages
+ #
+ def pages_to_list
+ # sort by fullpath first
+ list = self.pages.values.sort { |a, b| a.fullpath <=> b.fullpath }
+ # sort finally by depth
+ list.sort { |a, b| a.depth <=> b.depth }
+ end
+
+ def build_relationships(parent, list)
+ # do not use an empty template for other locales than the default one
+ parent.set_default_template_for_each_locale(self.default_locale)
+
+ list.dup.each do |page|
+ next unless self.is_subpage_of?(page.fullpath, parent.fullpath)
+
+ # attach the page to the parent (order by position), also set the parent
+ parent.add_child(page)
+
+ # localize the fullpath in all the locales
+ page.localize_fullpath
+
+ # remove the page from the list
+ list.delete(page)
+
+ # go under
+ self.build_relationships(page, list)
+ end
+ end
+
+ # Record pages found in file system
+ def all
+ [].tap do |page_records|
+ position, last_dirname = nil, nil
+
+ Dir.glob(File.join(@root_path, '**/*')).sort.each do |filepath|
+ next unless File.directory?(filepath) || filepath =~ /\.(#{Locomotive::Steam::TEMPLATE_EXTENSIONS.join('|')})$/
+
+ if last_dirname != File.dirname(filepath)
+ position, last_dirname = 100, File.dirname(filepath)
+ end
+
+ page = page_attributes(filepath)
+ page[:position] = position
+
+ page_records << page
+ position += 1
+ end
+ end
+ end
+
+ def page_attributes(filepath)
+ {}.tap do |attributes|
+ fullpath = self.filepath_to_fullpath(filepath)
+ attributes[:title] = File.basename(fullpath).humanize
+ attributes[:fullpath] = fullpath
+ attributes[:template] = OpenStruct.new(raw_source: '') if File.directory?(filepath)
+ attributes.merge(get_attributes_from_header(filepath)) unless File.directory?(filepath)
+ end
+ end
+
+ # Set attributes of a page from the information
+ # stored in the header of the template (YAML matters).
+ # It also stores the template.
+ #
+ # @param [ Object ] page The page
+ # @param [ String ] filepath The path of the template
+ #
+ def get_attributes_from_header(filepath)
+ {}.tap do |attributes|
+ template = Locomotive::Steam::Utils::YAMLFrontMattersTemplate.new(filepath)
+
+ if template.attributes
+ attributes.merge(template.attributes)
+
+ if content_type_slug = attributes.delete('content_type')
+ attributes[:templatized] = true
+ attributes[:content_type] = Locomotive::Models[:content_types][content_type_slug]
+ end
+ end
+
+ attributes[:template] = template
+ end
+ end
+
+ # Return the directory where all the templates of
+ # pages are stored in the filesystem.
+ #
+ # @return [ String ] The root directory
+ #
+ def root_dir
+ @path
+ end
+
+ # Take the path to a file on the filesystem
+ # and return its matching value for a Page.
+ #
+ # @param [ String ] filepath The path to the file
+ #
+ # @return [ String ] The fullpath of the page
+ #
+ def filepath_to_fullpath(filepath)
+ fullpath = filepath.gsub(File.join(self.root_dir, '/'), '')
+
+ fullpath.gsub!(/^\.\//, '')
+
+ fullpath.split('.').first.dasherize
+ end
+
+ # Tell is a page described by its fullpath is a sub page of a parent page
+ # also described by its fullpath
+ #
+ # @param [ String ] fullpath The full path of the page to test
+ # @param [ String ] parent_fullpath The full path of the parent page
+ #
+ # @return [ Boolean] True if the page is a sub page of the parent one
+ #
+ def is_subpage_of?(fullpath, parent_fullpath)
+ return false if %w(index 404).include?(fullpath)
+
+ if parent_fullpath == 'index' && fullpath.split('/').size == 1
+ return true
+ end
+
+ File.dirname(fullpath.dasherize) == parent_fullpath.dasherize
+ end
+ end
+ end
+ end
+ end
+ end
locomotive/steam/loaders/yml/site_loader.rb b/lib/locomotive/steam/loaders/yml/site_loader.rb +41 -0
@@ @@ -0,0 +1,41 @@
+ module Locomotive
+ module Steam
+ module Loader
+ module Yml
+ class SiteLoader
+ def initialize(path, mapper)
+ @root_path = path
+ @path = File.join(@root_path, 'config', 'site.yml')
+ @mapper = mapper
+ end
+
+ def load!
+ entity_class = @mapper.collection(:sites).entity
+ repository = @mapper.collection(:sites).repository
+ all.each do |site_hash|
+ site = entity_class.new(site_hash)
+ repository.create site, site_hash['locales'].first
+ end
+ end
+
+ private
+
+ def all
+ attributes = load_attributes
+ (attributes['domains'] ||= []) << '0.0.0.0'
+ [attributes]
+ end
+
+ def load_attributes
+ if File.exists?(@path)
+ file = File.read(@path).force_encoding('utf-8')
+ YAML::load(file)
+ else
+ raise "#{@path} was not found"
+ end
+ end
+ end
+ end
+ end
+ end
+ end
locomotive/steam/loaders/yml/utils/yaml_front_matters_template.rb b/lib/locomotive/steam/loaders/yml/utils/yaml_front_matters_template.rb +45 -0
@@ @@ -0,0 +1,45 @@
+ module Locomotive
+ module Steam
+ module Utils
+
+ # YAML Front-matters for HAML/Liquid templates
+ class YAMLFrontMattersTemplate
+
+ attr_accessor :filepath, :attributes, :raw_source, :line_offset
+
+ def initialize(filepath)
+ self.filepath = filepath
+ self.line_offset = 0
+
+ self.fetch_attributes_and_raw_source(File.read(self.filepath))
+ end
+
+ def source
+ return @source if @source
+
+ @source = if self.filepath.ends_with?('.haml')
+ Haml::Engine.new(self.raw_source).render
+ else
+ self.raw_source
+ end
+ end
+
+ protected
+
+ def fetch_attributes_and_raw_source(data)
+ if data =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)(.*)/m
+ self.line_offset = $1.count("\n") + 1
+ self.attributes = YAML.load($1)
+ self.raw_source = $3
+ else
+ self.attributes = nil
+ self.raw_source = data
+ end
+
+ self.raw_source = self.raw_source.force_encoding('utf-8')
+ end
+
+ end
+ end
+ end
+ end
locomotive/steam/loaders/yml_loader.rb b/lib/locomotive/steam/loaders/yml_loader.rb +32 -0
@@ @@ -0,0 +1,32 @@
+ require_relative 'yml/site_loader'
+ require_relative 'yml/pages_loader'
+ require_relative 'yml/utils/yaml_front_matters_template'
+
+ module Locomotive
+ module Steam
+ module Loader
+ class YmlLoader
+
+ MODELS = %W[site]
+
+ def initialize path, mapper
+ @root_path, @mapper = path, mapper
+ end
+
+ def load!
+ load_site!
+ load_pages!
+ end
+
+ def load_site!
+ Locomotive::Steam::Loader::Yml::SiteLoader.new(@root_path, @mapper).load!
+ end
+
+ def load_pages!
+ Locomotive::Steam::Loader::Yml::PagesLoader.new(@root_path, @mapper).load!
+ end
+
+ end
+ end
+ end
+ end
spec/spec_helper.rb +11 -2
@@ @@ -1,10 +1,16 @@
require 'rubygems'
require 'bundler/setup'
- require 'common'
+ require 'locomotive/common'
require 'i18n-spec'
require 'coveralls'
+ begin
+ require 'pry'
+ rescue LoadError
+ end
+
+
require_relative '../lib/locomotive/steam'
require_relative 'support'
@@ @@ -17,6 +23,9 @@ RSpec.configure do |config|
config.run_all_when_everything_filtered = true
config.before(:all) { remove_logs }
- config.before { reset! }
+ config.before do
+ reset!
+ bootstrap_site
+ end
config.after { reset! }
end
spec/support/helpers.rb +16 -8
@@ @@ -1,9 +1,18 @@
- require 'common'
+ require 'locomotive/common'
+ require 'locomotive/models'
require_relative '../../lib/locomotive/steam/initializers'
+ require_relative '../../lib/locomotive/steam/loaders/yml_loader'
module Spec
module Helpers
+ def bootstrap_site
+ adapter = Locomotive::Adapters::MemoryAdapter
+ mapper = Locomotive::Mapper.load_from_file! adapter, File.join(File.expand_path('lib/locomotive/steam/mapper.rb'))
+ mapper.load!
+ Locomotive::Steam::Loader::YmlLoader.new(site_path, mapper).load!
+ end
+
def reset!
FileUtils.rm_rf(File.expand_path('../../../site', __FILE__))
end
@@ @@ -15,17 +24,16 @@ module Spec
def run_server
Locomotive::Common.reset
Locomotive::Common.configure do |config|
- path = File.join(File.expand_path('../../spec/fixtures/default/log/locomotivecms.log'))
+ path = File.join(site_path, 'log/locomotivecms.log')
config.notifier = Locomotive::Common::Logger.setup(path)
end
Locomotive::Common::Logger.info 'Server started...'
-
- reader = Locomotive::Mounter::Reader::FileSystem.instance
- reader.run!(path: 'spec/fixtures/default')
-
- Locomotive::Steam::Server.new(reader)
+ Locomotive::Steam::Server.new(path: site_path)
end
+ def site_path
+ File.expand_path('../../fixtures/default/', __FILE__)
+ end
end
- end
\ No newline at end of file
+ end