robin-drexler/cosch

View on GitHub
lib/commands/build.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'liquid'
require 'fileutils'
require 'yaml'
require 'json'
require_relative '../appcache_path_generator'
require_relative '../location_data_generator'
require 'find'

VIEW_PATH_ROOT = File.join('views')

module RapidSchedule
  module Commands
    class Build
      def execute!
        p 'Building site'
        @config = read_config
        @days = days = @config["days"]
        @location_data_generator = RapidSchedule::LocationDataGenerator.new(@days)

        Liquid::Template.file_system = Liquid::LocalFileSystem.new(VIEW_PATH_ROOT)


        @days = decorate_days_with_file_names(days)

        FileUtils.mkdir_p('build/')
        FileUtils.rm_rf(Dir.glob('build/*'))


        @days.each do |day|
          create_day_view_for_day(day, @location_data_generator.locations_for_day(day))
          create_location_views_for_day(day)
        end

        copy_static_to_build
        write_schedule_json

        appcache_generator = AppcachePathGenerator.new 'build'
        appcache_content = generate_appcache_content(appcache_generator.paths)

        appcache_content << "#VERSION:" + appcache_generator.appcache_version + '#'

        File.write('build/' + 'cache.appcache', appcache_content)
      end


      private

      def read_config
        YAML.load_file 'schedule.yml'
      end

      def create_day_view_for_day(day, locations)
        day_html = generate_day_html(day, locations)
        write_with_wrapper_markup(day_html, 'build/' + day['file_name'] + '.html')
      end

      def create_location_views_for_day(day)
        locations = @location_data_generator.locations_for_day(day)

        locations.each do |location|
          html = generate_location_html(location, @location_data_generator.talks_for_location_for_day(location, day), day)
          write_with_wrapper_markup(html, generate_location_path_for_day(day, location))
        end

      end

      def generate_location_html(location, talks, day)
        html_path = File.join(VIEW_PATH_ROOT, 'location.html')
        file_content = File.new(html_path).read

        Liquid::Template.parse(file_content).render(
          {
            'day' => day,
            'talks' => talks,
            'days' => @days,
            'title' => @config['title'],
            'location' => location
          })
      end

      def generate_location_path_for_day(day, location)
        'build/' + day['file_name'] + '_' + sanitize_filename(location) + '.html'
      end

      # XXX file names not unique anymore! Could be overridden
      def decorate_days_with_file_names(days)
        days_decorated = days.map do |day|
          index = days.index day
          day['file_name'] = sanitize_filename(day["name"])

          if index === 0
            day['file_name'] = 'index'
          end

          # sanitize location paths
          day['slots'].each do |slot|
            slot['talks'].each do |talk|
              talk['location_file_name'] = sanitize_filename(talk['location'])
            end
          end

          day
        end
      end

      def write_with_wrapper_markup(html, path)
        wrapper_path = File.join(VIEW_PATH_ROOT, 'wrapper.html')
        html = Liquid::Template.parse(File.new(wrapper_path).read).render('content' => html)

        File.write(path, html)
      end

      def generate_day_html(day, locations)
        html_path = File.join(VIEW_PATH_ROOT, 'day.html')
        file_content = File.new(html_path).read

        Liquid::Template.parse(file_content).render(
          {
            'day' => day,
            'days' => @days,
            'active_name' => day['name'],
            'title' => @config['title']
          })
      end

      def generate_appcache_content(paths)
        Liquid::Template.parse(File.new(File.join(VIEW_PATH_ROOT, 'cache.appcache')).read).render 'resources' => paths
      end

      def copy_static_to_build
        static_folder_path = 'static'

        return unless Dir.exist? static_folder_path

        FileUtils.cp_r(Dir[static_folder_path + '/*'], 'build')
      end

      def write_schedule_json
        json = JSON.dump(read_config)
        File.write('build/schedule.json', json)
      end

      def sanitize_filename(filename)
        # Split the name when finding a period which is preceded by some
        # character, and is followed by some character other than a period,
        # if there is no following period that is followed by something
        # other than a period (yeah, confusing, I know)
        fn = filename.split /(?<=.)\.(?=[^.])(?!.*\.[^.])/m

        # We now have one or two parts (depending on whether we could find
        # a suitable period). For each of these parts, replace any unwanted
        # sequence of characters with an underscore
        fn.map! { |s| s.gsub /[^a-z0-9\-]+/i, '_' }

        # Finally, join the parts with a period and return the result
        return fn.join '.'
      end
    end
  end
end