playgroundbook 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +50 -0
 - data/.rspec +2 -0
 - data/.rubocop.yml +2 -0
 - data/.ruby-version +1 -0
 - data/Changelog.md +17 -0
 - data/Gemfile +12 -0
 - data/Gemfile.lock +103 -0
 - data/Guardfile +14 -0
 - data/LICENSE +21 -0
 - data/README.md +92 -0
 - data/Rakefile +8 -0
 - data/bin/playgroundbook +22 -0
 - data/lib/playgroundbook.rb +9 -0
 - data/lib/playgroundbook_lint/abstract_linter.rb +23 -0
 - data/lib/playgroundbook_lint/chapter_linter.rb +34 -0
 - data/lib/playgroundbook_lint/chapter_manifest_linter.rb +43 -0
 - data/lib/playgroundbook_lint/contents_linter.rb +20 -0
 - data/lib/playgroundbook_lint/cutscene_page_linter.rb +17 -0
 - data/lib/playgroundbook_lint/cutscene_page_manifest_linter.rb +18 -0
 - data/lib/playgroundbook_lint/manifest_linter.rb +39 -0
 - data/lib/playgroundbook_lint/page_linter.rb +23 -0
 - data/lib/playgroundbook_lint/page_manifest_linter.rb +18 -0
 - data/lib/playgroundbook_lint/playgroundbook_lint.rb +31 -0
 - data/lib/playgroundbook_lint/root_manifest_linter.rb +36 -0
 - data/lib/playgroundbook_renderer/chapter_collator.rb +77 -0
 - data/lib/playgroundbook_renderer/contents_manifest_generator.rb +33 -0
 - data/lib/playgroundbook_renderer/page_writer.rb +34 -0
 - data/lib/playgroundbook_renderer/playgroundbook_renderer.rb +75 -0
 - data/lib/version.rb +3 -0
 - data/playground_book_lint.gemspec +21 -0
 - data/spec/fixtures/Starter.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Manifest.plist +15 -0
 - data/spec/fixtures/Starter.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift +8 -0
 - data/spec/fixtures/Starter.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Manifest.plist +12 -0
 - data/spec/fixtures/Starter.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page2.playgroundpage/Contents.swift +8 -0
 - data/spec/fixtures/Starter.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page2.playgroundpage/Manifest.plist +12 -0
 - data/spec/fixtures/Starter.playgroundbook/Contents/Manifest.plist +20 -0
 - data/spec/fixtures/assets/file.jpeg +0 -0
 - data/spec/fixtures/book.yml +5 -0
 - data/spec/fixtures/test_chapter.playground/Contents.swift +17 -0
 - data/spec/fixtures/test_chapter.playground/contents.xcplayground +4 -0
 - data/spec/playground_book_lint/chapter_linter_spec.rb +30 -0
 - data/spec/playground_book_lint/chapter_manifest_linter_spec.rb +40 -0
 - data/spec/playground_book_lint/contents_linter_spec.rb +18 -0
 - data/spec/playground_book_lint/cutscene_page_linter_spec.rb +14 -0
 - data/spec/playground_book_lint/cutscene_page_manifest_linter_spec.rb +63 -0
 - data/spec/playground_book_lint/manfiest_linter_spec.rb +71 -0
 - data/spec/playground_book_lint/page_linter_spec.rb +19 -0
 - data/spec/playground_book_lint/page_manifest_linter_spec.rb +43 -0
 - data/spec/playground_book_lint/playgroundbook_lint_spec.rb +38 -0
 - data/spec/playground_book_lint/root_manifest_linter_spec.rb +35 -0
 - data/spec/playgroundbook_renderer_spec/chapter_collator_spec.rb +70 -0
 - data/spec/playgroundbook_renderer_spec/contents_manfiest_generator_spec.rb +37 -0
 - data/spec/playgroundbook_renderer_spec/page_writer_spec.rb +57 -0
 - data/spec/playgroundbook_renderer_spec/playgroundbook_renderer_spec.rb +112 -0
 - data/spec/spec_helper.rb +75 -0
 - metadata +141 -0
 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'playgroundbook_lint/manifest_linter'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/page_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'playgroundbook_lint/cutscene_page_linter'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 6 
     | 
    
         
            +
              # A linter for verifying the contents of a chapter's Manifest.plist
         
     | 
| 
      
 7 
     | 
    
         
            +
              class ChapterManifestLinter < ManifestLinter
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :page_linter, :cutscene_page_linter
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(page_linter = PageLinter.new, cutscene_page_linter = CutscenePageLinter.new)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @page_linter = page_linter
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @cutscene_page_linter = cutscene_page_linter
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 16 
     | 
    
         
            +
                  super()
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  fail_lint "Chapter has no pages in #{Dir.pwd}" unless chapter_has_manifest_pages?
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  manifest_plist_contents['Pages'].each do |page_directory_name|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    # All pages exist inside the /Pages subdirectory, we need to chdir to there first.
         
     | 
| 
      
 22 
     | 
    
         
            +
                    Dir.chdir PAGES_DIRECTORY_NAME do
         
     | 
| 
      
 23 
     | 
    
         
            +
                      fail_lint "Chapter page directory #{page_directory_name} missing in #{Dir.pwd}" unless Dir.exist?(page_directory_name)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      lint_page page_directory_name
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def lint_page(page_directory_name)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  Dir.chdir page_directory_name do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    if page_directory_name =~ /.+\.playgroundpage$/
         
     | 
| 
      
 32 
     | 
    
         
            +
                      page_linter.lint
         
     | 
| 
      
 33 
     | 
    
         
            +
                    elsif page_directory_name =~ /.+\.cutscenepage$/
         
     | 
| 
      
 34 
     | 
    
         
            +
                      cutscene_page_linter.lint
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def chapter_has_manifest_pages?
         
     | 
| 
      
 40 
     | 
    
         
            +
                  value_defined_in_manifest?('Pages')
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'playgroundbook_lint/abstract_linter'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/root_manifest_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A linter for verifying the contents directory of a playground book
         
     | 
| 
      
 6 
     | 
    
         
            +
              class ContentsLinter < AbstractLinter
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :root_manfiest_linter
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(root_manfiest_linter = RootManifestLinter.new)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @root_manfiest_linter = root_manfiest_linter
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 14 
     | 
    
         
            +
                  Dir.chdir 'Contents' do
         
     | 
| 
      
 15 
     | 
    
         
            +
                    root_manfiest_linter.lint
         
     | 
| 
      
 16 
     | 
    
         
            +
                    # TODO: Other linting?
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'playgroundbook_lint/abstract_linter'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/cutscene_page_manifest_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A linter for verifying cutscene pages
         
     | 
| 
      
 6 
     | 
    
         
            +
              class CutscenePageLinter < AbstractLinter
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :cutscene_page_manifest_linter
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(cutscene_page_manifest_linter = CutscenePageManifestLinter.new)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @cutscene_page_manifest_linter = cutscene_page_manifest_linter
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 14 
     | 
    
         
            +
                  cutscene_page_manifest_linter.lint
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'playgroundbook_lint/manifest_linter'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 4 
     | 
    
         
            +
              # A linter for verifying the contents of a cutscene page's manifest
         
     | 
| 
      
 5 
     | 
    
         
            +
              class CutscenePageManifestLinter < ManifestLinter
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :page_manifest_linter
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 9 
     | 
    
         
            +
                  super()
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  # Cutscene references should point to an existent HTML file
         
     | 
| 
      
 12 
     | 
    
         
            +
                  cutscene_reference = manifest_plist_contents['CutsceneReference']
         
     | 
| 
      
 13 
     | 
    
         
            +
                  fail_lint "Cutscene manifest doesn't reference a cutscene file" if cutscene_reference.nil?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  fail_lint "Cutscene file at '#{cutscene_reference}' isn't HTML" unless cutscene_reference =~ /^.+\.html$/i
         
     | 
| 
      
 15 
     | 
    
         
            +
                  fail_lint "Cutscene file at '#{cutscene_reference}' doesn't exist" unless File.exist? cutscene_reference
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'plist'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/abstract_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 5 
     | 
    
         
            +
              MANIFEST_FILE_NAME = 'Manifest.plist'.freeze
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              # A base inplementation of a linter for verifying the contents of manifest
         
     | 
| 
      
 8 
     | 
    
         
            +
              # files.
         
     | 
| 
      
 9 
     | 
    
         
            +
              class ManifestLinter < AbstractLinter
         
     | 
| 
      
 10 
     | 
    
         
            +
                # TODO: Should load manifest file in initialize instead of lazily.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 13 
     | 
    
         
            +
                  fail_lint "No Manifest file in #{Dir.pwd}" unless manifest_file_exists?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  fail_lint "Manifest file missing Name in #{Dir.pwd}" unless name?
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def manifest_file_exists?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  File.exist? MANIFEST_FILE_NAME
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def manifest_plist_contents
         
     | 
| 
      
 22 
     | 
    
         
            +
                  return @manifest_plist_contents unless @manifest_plist_contents.nil?
         
     | 
| 
      
 23 
     | 
    
         
            +
                  require 'plist'
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @manifest_plist_contents = Plist.parse_xml(MANIFEST_FILE_NAME)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @manifest_plist_contents
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def name?
         
     | 
| 
      
 29 
     | 
    
         
            +
                  value_defined_in_manifest?('Name')
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def value_defined_in_manifest?(key)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  return false if manifest_plist_contents.nil?
         
     | 
| 
      
 34 
     | 
    
         
            +
                  return false if manifest_plist_contents[key].nil?
         
     | 
| 
      
 35 
     | 
    
         
            +
                  return false if manifest_plist_contents[key].empty?
         
     | 
| 
      
 36 
     | 
    
         
            +
                  true
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'playgroundbook_lint/abstract_linter'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/page_manifest_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A linter for verifying the contents of a page directory
         
     | 
| 
      
 6 
     | 
    
         
            +
              class PageLinter < AbstractLinter
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :page_manifest_linter
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(page_manifest_linter = PageManifestLinter.new)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @page_manifest_linter = page_manifest_linter
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 14 
     | 
    
         
            +
                  fail_lint "Missing #{ContentsSwiftFileName} in #{Dir.pwd}" unless contents_swift_file_exists?
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  page_manifest_linter.lint
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def contents_swift_file_exists?
         
     | 
| 
      
 20 
     | 
    
         
            +
                  File.exist? ContentsSwiftFileName
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'plist'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/manifest_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 5 
     | 
    
         
            +
              # A linter for verifying the contents of a page's Manifest.plist
         
     | 
| 
      
 6 
     | 
    
         
            +
              class PageManifestLinter < ManifestLinter
         
     | 
| 
      
 7 
     | 
    
         
            +
                SUPPORTED_LIVE_VIEW_MODES = %w(VisibleByDefault HiddenByDefault).freeze
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super()
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  live_view_mode = manifest_plist_contents['LiveViewMode']
         
     | 
| 
      
 13 
     | 
    
         
            +
                  unless live_view_mode.nil?
         
     | 
| 
      
 14 
     | 
    
         
            +
                    fail_lint "Unsopported LiveViewMoode '#{live_view_mode}'" unless SUPPORTED_LIVE_VIEW_MODES.include? live_view_mode
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'colored'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/abstract_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'playgroundbook_lint/contents_linter'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'pathname'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 7 
     | 
    
         
            +
              # A linter for verifying a playground book
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Linter < AbstractLinter
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_accessor :playground_file_name
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_accessor :contents_linter
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(playground_file_name, contents_linter = ContentsLinter.new)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @playground_file_name = playground_file_name
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @contents_linter = contents_linter
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 18 
     | 
    
         
            +
                  message "Validating #{playground_file_name.yellow}..."
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  fail_lint 'No Contents directory' unless contents_dir_exists?
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  Dir.chdir playground_file_name do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    contents_linter.lint
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def contents_dir_exists?
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Dir.exist?(playground_file_name + '/Contents')
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'plist'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_lint/manifest_linter'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'playgroundbook_lint/chapter_linter'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 6 
     | 
    
         
            +
              # A linter for verifying the contents of a playground book's root manifest
         
     | 
| 
      
 7 
     | 
    
         
            +
              class RootManifestLinter < ManifestLinter
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :chapter_linter
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(chapter_linter = ChapterLinter.new)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @chapter_linter = chapter_linter
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def lint
         
     | 
| 
      
 15 
     | 
    
         
            +
                  super()
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  fail_lint 'No Chapters directory' unless chapters_directory_exist?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  fail_lint 'No Chapters specified' unless chapters_exist?
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  # Go into Chapters/ and then each chapter directory, then lint it.
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Dir.chdir 'Chapters' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                    manifest_plist_contents['Chapters'].each do |chapter_directory_name|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      chapter_linter.lint(chapter_directory_name)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def chapters_directory_exist?
         
     | 
| 
      
 29 
     | 
    
         
            +
                  Dir.exist? 'Chapters'
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def chapters_exist?
         
     | 
| 
      
 33 
     | 
    
         
            +
                  value_defined_in_manifest?('Chapters')
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,77 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'plist'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'playgroundbook_renderer/page_writer'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 5 
     | 
    
         
            +
              SharedSourcesDirectoryName = 'Sources'
         
     | 
| 
      
 6 
     | 
    
         
            +
              PreambleFileName = 'Preamble.swift'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              class ChapterCollator
         
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(page_writer = PageWriter.new, ui = Cork::Board.new)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @page_writer = page_writer
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @ui = ui
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def collate!(chapter_name, chapter_file_contents, imports)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @ui.puts "Processing #{chapter_name.green}."
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  chater_directory_name = "#{chapter_name}.playgroundchapter"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Dir.mkdir(chater_directory_name) unless Dir.exist?(chater_directory_name)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  Dir.chdir(chater_directory_name) do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    pages = parse_pages(chapter_file_contents)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    
         
     | 
| 
      
 22 
     | 
    
         
            +
                    Dir.mkdir(PagesDirectoryName) unless Dir.exist?(PagesDirectoryName)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    Dir.chdir(PagesDirectoryName) do
         
     | 
| 
      
 24 
     | 
    
         
            +
                      pages[:page_names].each_with_index do |page_name, index|
         
     | 
| 
      
 25 
     | 
    
         
            +
                        @ui.puts "  Processing #{page_name.green}."
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                        page_contents = pages[:page_contents][index]
         
     | 
| 
      
 28 
     | 
    
         
            +
                        page_dir_name = pages[:page_dir_names][index]
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                        @page_writer.write_page!(page_name, page_dir_name, imports, page_contents)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    write_chapter_manifest!(chapter_name, pages[:page_dir_names])
         
     | 
| 
      
 35 
     | 
    
         
            +
                    write_preamble!(pages[:preamble])
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def parse_pages(swift)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  page_names = swift.scan(/\/\/\/\/.*$/).map { |p| p.gsub('////', '').strip }
         
     | 
| 
      
 41 
     | 
    
         
            +
                  page_dir_names = page_names.map { |p| "#{p}.playgroundpage" }
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  split_file = swift.split(/\/\/\/\/.*$/)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  page_contents = split_file.drop(1).map { |p| p.strip }
         
     | 
| 
      
 45 
     | 
    
         
            +
                  preamble = split_file.first.strip
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  {
         
     | 
| 
      
 48 
     | 
    
         
            +
                    page_dir_names: page_dir_names,
         
     | 
| 
      
 49 
     | 
    
         
            +
                    page_names: page_names,
         
     | 
| 
      
 50 
     | 
    
         
            +
                    page_contents: page_contents,
         
     | 
| 
      
 51 
     | 
    
         
            +
                    preamble: preamble,
         
     | 
| 
      
 52 
     | 
    
         
            +
                  }
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def write_chapter_manifest!(chapter_name, page_dir_names)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  manifest_contents = {
         
     | 
| 
      
 57 
     | 
    
         
            +
                    'Name' => chapter_name,
         
     | 
| 
      
 58 
     | 
    
         
            +
                    'Pages' => page_dir_names,
         
     | 
| 
      
 59 
     | 
    
         
            +
                    'Version' => '1.0',
         
     | 
| 
      
 60 
     | 
    
         
            +
                    'ContentVersion' => '1.0',
         
     | 
| 
      
 61 
     | 
    
         
            +
                  }
         
     | 
| 
      
 62 
     | 
    
         
            +
                  File.open(ManifestFileName, 'w') do |file|
         
     | 
| 
      
 63 
     | 
    
         
            +
                    file.write(manifest_contents.to_plist)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def write_preamble!(preamble)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  Dir.mkdir(SharedSourcesDirectoryName) unless Dir.exist?(SharedSourcesDirectoryName)
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  Dir.chdir(SharedSourcesDirectoryName) do
         
     | 
| 
      
 71 
     | 
    
         
            +
                    File.open(PreambleFileName, 'w') do |file|
         
     | 
| 
      
 72 
     | 
    
         
            +
                      file.write(preamble)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
              end
         
     | 
| 
      
 77 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'plist'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 4 
     | 
    
         
            +
              class ContentsManifestGenerator
         
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(ui = Cork::Board.new)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @ui = ui
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def generate!(book_metadata)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @ui.puts "Generating main manifest file."
         
     | 
| 
      
 11 
     | 
    
         
            +
                  write_manifest_file!(book_metadata)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @ui.puts "Manifest file generated."
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def write_manifest_file!(book_metadata)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  File.open(ManifestFileName, 'w') do |file|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    file.write(manifest_contents(book_metadata).to_plist)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def manifest_contents(book_metadata)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  chapters = book_metadata['chapters'].map{ |c| "#{c}.playgroundchapter" }
         
     | 
| 
      
 23 
     | 
    
         
            +
                  {
         
     | 
| 
      
 24 
     | 
    
         
            +
                    'Name' => book_metadata['name'],
         
     | 
| 
      
 25 
     | 
    
         
            +
                    'ContentIdentifier' => book_metadata['identifier'],
         
     | 
| 
      
 26 
     | 
    
         
            +
                    'DeploymentTarget' => book_metadata['deployment_target'] || 'ios10.0',
         
     | 
| 
      
 27 
     | 
    
         
            +
                    'Chapters' => chapters,
         
     | 
| 
      
 28 
     | 
    
         
            +
                    'Version' => '1.0',
         
     | 
| 
      
 29 
     | 
    
         
            +
                    'ContentVersion' => '1.0',
         
     | 
| 
      
 30 
     | 
    
         
            +
                  }
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'plist'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 4 
     | 
    
         
            +
              class PageWriter
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(ui = Cork::Board.new)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @ui = ui
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def write_page!(page_name, page_dir_name, imports, page_contents)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  Dir.mkdir(page_dir_name) unless Dir.exist?(page_dir_name)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  contents_with_import = "//#-hidden-code\n"
         
     | 
| 
      
 14 
     | 
    
         
            +
                  contents_with_import += imports.map { |i| "import #{i}" }.join("\n") + "\n"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  contents_with_import += "//#-end-hidden-code\n"
         
     | 
| 
      
 16 
     | 
    
         
            +
                  contents_with_import += page_contents
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  Dir.chdir(page_dir_name) do
         
     | 
| 
      
 19 
     | 
    
         
            +
                    File.open(ContentsSwiftFileName, 'w') do |file|
         
     | 
| 
      
 20 
     | 
    
         
            +
                      file.write(contents_with_import)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    File.open(MANIFEST_FILE_NAME, 'w') do |file|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      file.write ({
         
     | 
| 
      
 25 
     | 
    
         
            +
                        'Name' => page_name,
         
     | 
| 
      
 26 
     | 
    
         
            +
                        'LiveViewMode' => 'HiddenByDefault',
         
     | 
| 
      
 27 
     | 
    
         
            +
                        'Version' => '1.0',
         
     | 
| 
      
 28 
     | 
    
         
            +
                        'ContentVersion' => '1.0',
         
     | 
| 
      
 29 
     | 
    
         
            +
                      }.to_plist)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'colored'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'pathname'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'playgroundbook_renderer/contents_manifest_generator'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'playgroundbook_renderer/chapter_collator'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Playgroundbook
         
     | 
| 
      
 9 
     | 
    
         
            +
              ContentsDirName = 'Contents'
         
     | 
| 
      
 10 
     | 
    
         
            +
              ChaptersDirName = 'Chapters'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              # A renderer for playground books.
         
     | 
| 
      
 13 
     | 
    
         
            +
              class Renderer < AbstractLinter
         
     | 
| 
      
 14 
     | 
    
         
            +
                attr_accessor :yaml_file_name
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_accessor :contents_manifest_generator
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_accessor :chapter_collator
         
     | 
| 
      
 17 
     | 
    
         
            +
                attr_accessor :ui
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def initialize(yaml_file_name, 
         
     | 
| 
      
 20 
     | 
    
         
            +
                    contents_manifest_generator = ContentsManifestGenerator.new, 
         
     | 
| 
      
 21 
     | 
    
         
            +
                    chapter_collator = ChapterCollator.new,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    ui = Cork::Board.new)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @yaml_file_name = yaml_file_name
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @contents_manifest_generator = contents_manifest_generator
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @chapter_collator = chapter_collator
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @ui = ui
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def render!
         
     | 
| 
      
 30 
     | 
    
         
            +
                  ui.puts "Rendering #{yaml_file_name.green}..."
         
     | 
| 
      
 31 
     | 
    
         
            +
                  
         
     | 
| 
      
 32 
     | 
    
         
            +
                  book = yaml_contents
         
     | 
| 
      
 33 
     | 
    
         
            +
                  book_dir_name = "#{book['name']}.playgroundbook"
         
     | 
| 
      
 34 
     | 
    
         
            +
                  book_chapter_contents = []
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # TODO: Validate YAML contents?
         
     | 
| 
      
 36 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 37 
     | 
    
         
            +
                    book_chapter_contents = book['chapters'].map do |chapter|
         
     | 
| 
      
 38 
     | 
    
         
            +
                      File.read("#{chapter}.playground/Contents.swift")
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  rescue => e
         
     | 
| 
      
 41 
     | 
    
         
            +
                    ui.puts 'Failed to open playground Contents.swift file.'
         
     | 
| 
      
 42 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  Dir.mkdir(book_dir_name) unless Dir.exist?(book_dir_name)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  Dir.chdir(book_dir_name) do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    Dir.mkdir(ContentsDirName) unless Dir.exist?(ContentsDirName)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    Dir.chdir(ContentsDirName) do
         
     | 
| 
      
 49 
     | 
    
         
            +
                      resources_dir = book['resources']
         
     | 
| 
      
 50 
     | 
    
         
            +
                      if !(resources_dir.nil? || resources_dir.empty?)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        @ui.puts "Copying resource directory (#{resources_dir.green}) contents."
         
     | 
| 
      
 52 
     | 
    
         
            +
                        Dir.mkdir(ResourcesDirectoryName) unless Dir.exist?(ResourcesDirectoryName)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        Dir.glob("../../#{resources_dir}/*").each do |file|
         
     | 
| 
      
 54 
     | 
    
         
            +
                          FileUtils.cp(file, ResourcesDirectoryName)
         
     | 
| 
      
 55 
     | 
    
         
            +
                        end
         
     | 
| 
      
 56 
     | 
    
         
            +
                      end
         
     | 
| 
      
 57 
     | 
    
         
            +
                      @contents_manifest_generator.generate!(book)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                      Dir.mkdir(ChaptersDirName) unless Dir.exist?(ChaptersDirName)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      Dir.chdir(ChaptersDirName) do
         
     | 
| 
      
 61 
     | 
    
         
            +
                        # Chapter file name becomes chapter name in playground book.
         
     | 
| 
      
 62 
     | 
    
         
            +
                        book['chapters'].each_with_index do |chapter_file_name, index|
         
     | 
| 
      
 63 
     | 
    
         
            +
                          chapter_file_contents = book_chapter_contents[index]
         
     | 
| 
      
 64 
     | 
    
         
            +
                          @chapter_collator.collate!(chapter_file_name, chapter_file_contents, book['imports'] || ['UIKit'])
         
     | 
| 
      
 65 
     | 
    
         
            +
                        end
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def yaml_contents
         
     | 
| 
      
 72 
     | 
    
         
            +
                  YAML.load(File.open(@yaml_file_name))
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
            end
         
     |