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 |