New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial work on Rendering #15
Changes from all commits
e21d2e8
cfdce4f
57252f2
d9690b7
bd8ec5e
40bdf6f
8eda4c0
0e3a986
9f7da0e
b5f3059
194df71
7793899
e791a1d
75746b9
d9e51e2
482d497
ab0981d
237c3d3
fdd8f2d
1ac6605
301eee2
e01caa0
e4e62dc
0fe75ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
ruby-2.0.0-p247 | ||
ruby-2.1.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,92 @@ | ||
[![CircleCI](https://circleci.com/gh/ashfurrow/playground-book-lint.svg?style=svg)](https://circleci.com/gh/ashfurrow/playground-book-lint) | ||
|
||
# playground-book-lint | ||
# playgroundbook | ||
|
||
Linter for Swift Playground books based on [Apple's documentation](https://developer.apple.com/library/prerelease/content/documentation/Xcode/Conceptual/swift_playgrounds_doc_format/index.html#//apple_ref/doc/uid/TP40017343-CH47-SW4). It's a work in progress (see [issues](https://github.com/ashfurrow/playground-book-lint/issues)) but you can use it now. | ||
|
||
## Installation | ||
|
||
```sh | ||
> [sudo] gem install playground-book-lint | ||
> [sudo] gem install playgroundbook | ||
``` | ||
|
||
## Usage | ||
|
||
To lint an existing playground book: | ||
|
||
```sh | ||
> playground-book-lint MyPlaygroundBook.playgroundbook | ||
> playgroundbook lint MyPlaygroundbook.playgroundbook | ||
``` | ||
|
||
To generate a playground book: | ||
|
||
```sh | ||
> playgroundbook render book.yaml | ||
``` | ||
|
||
The yml file should be in the following format: | ||
|
||
```yaml | ||
name: Testing book | ||
identifier: com.ashfurrow.example | ||
resources: assets # Optional | ||
deployment_target: ios10.0 # Optional | ||
imports: # Optional, defaults to UIKit | ||
- UIKit | ||
- CoreGraphics | ||
chapters: | ||
- Chapter 1 | ||
- Chapter 2 | ||
- etc... | ||
``` | ||
|
||
Each chapter needs to have a corresponding playground; so `Chapter 1` requires there be a `Chapter 1.playground` playground. The playgrounds can reference (not copy) resources from an optionally specified directory. `import` frameworks are specified in the yaml file and are added to every page of the book. Each chapter needs to be in the following format: | ||
|
||
```swift | ||
// This is the preamble that is shared among all the pages within this chapter. | ||
|
||
func sharedFunc() { | ||
print("This should be accessible to all pages.") | ||
} | ||
|
||
//// Page 1 | ||
|
||
str = "Yo, it's page 1." | ||
sharedFunc() | ||
|
||
//// Page 2 | ||
|
||
sharedFunc() | ||
str = "Page 2 awww yeah." | ||
``` | ||
|
||
Pages are divided by lines beginning with a quadruple slash, followed by that pages name. | ||
|
||
### Limitations of Book Rendering | ||
|
||
Preamble (anything about the first `////` page) is put in its own file. That means declarations there need to be `public` to be visible within individual pages (even though when you're writing, everything is in one file). Additionally, the preamble is at the top-level and can't contain experessions. This would cause a compiler error in the Swift Playrounds iPad app: | ||
|
||
```swift | ||
public let layout = UICollectionViewFlowLayout() | ||
layout.itemSize = CGSize(width: 20, height: 20) | ||
``` | ||
|
||
Instead, you have to wrap it in a closure, like this: | ||
|
||
```swift | ||
public var layout: UICollectionViewFlowLayout = { | ||
let layout = UICollectionViewFlowLayout() | ||
layout.itemSize = CGSize(width: 20, height: 20) | ||
return layout | ||
}() | ||
``` | ||
|
||
It's awkward; if you have suggestions, open an issue :+1: | ||
|
||
Sharing resources is only available book-wide and not specific to chapters. Sharing code outside the preamble isn't supported yet. | ||
|
||
Playground books support a rich set of awesome features to make learning how to code really easy, and this tool uses almost none of them. It sacrifices this experience for the sake of being able to easily write the books on your Mac. | ||
|
||
## License | ||
|
||
MIT, except for the `starter.playgroundbook` in the unit tests, which is licensed by Apple. |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/usr/bin/env ruby | ||
|
||
unless ARGV.length >= 2 | ||
puts 'You must specify either lint or render. Example usage:' | ||
puts ' playgroundbook [lint|render] file_name' | ||
exit 1 | ||
end | ||
|
||
command = ARGV[0] | ||
file_name = ARGV[1] | ||
|
||
require 'playgroundbook' | ||
|
||
if command == 'lint' | ||
Playgroundbook::Linter.new(file_name).lint | ||
elsif command == 'render' | ||
Playgroundbook::Renderer.new(file_name).render! | ||
else | ||
puts "Unknown command: #{command}" | ||
exit 1 | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require 'playgroundbook_lint/playgroundbook_lint' | ||
require 'playgroundbook_renderer/playgroundbook_renderer' | ||
|
||
module Playgroundbook | ||
ManifestFileName = 'Manifest.plist'.freeze | ||
ContentsSwiftFileName = 'Contents.swift'.freeze | ||
ResourcesDirectoryName = 'Resources'.freeze | ||
PagesDirectoryName = 'Pages'.freeze | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
require 'colored' | ||
require 'cork' | ||
|
||
module PlaygroundBookLint | ||
module Playgroundbook | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious what the rationale behind the change from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It came from wanting to call the executable |
||
# AbstractLinter provides a base implementation of a linter which a concrete | ||
# linter subclass can inherit from | ||
class AbstractLinter | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
require 'plist' | ||
require 'playgroundbook_renderer/page_writer' | ||
|
||
module Playgroundbook | ||
SharedSourcesDirectoryName = 'Sources' | ||
PreambleFileName = 'Preamble.swift' | ||
|
||
class ChapterCollator | ||
def initialize(page_writer = PageWriter.new, ui = Cork::Board.new) | ||
@page_writer = page_writer | ||
@ui = ui | ||
end | ||
|
||
def collate!(chapter_name, chapter_file_contents, imports) | ||
@ui.puts "Processing #{chapter_name.green}." | ||
|
||
chater_directory_name = "#{chapter_name}.playgroundchapter" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
Dir.mkdir(chater_directory_name) unless Dir.exist?(chater_directory_name) | ||
Dir.chdir(chater_directory_name) do | ||
pages = parse_pages(chapter_file_contents) | ||
|
||
Dir.mkdir(PagesDirectoryName) unless Dir.exist?(PagesDirectoryName) | ||
Dir.chdir(PagesDirectoryName) do | ||
pages[:page_names].each_with_index do |page_name, index| | ||
@ui.puts " Processing #{page_name.green}." | ||
|
||
page_contents = pages[:page_contents][index] | ||
page_dir_name = pages[:page_dir_names][index] | ||
|
||
@page_writer.write_page!(page_name, page_dir_name, imports, page_contents) | ||
end | ||
end | ||
|
||
write_chapter_manifest!(chapter_name, pages[:page_dir_names]) | ||
write_preamble!(pages[:preamble]) | ||
end | ||
end | ||
|
||
def parse_pages(swift) | ||
page_names = swift.scan(/\/\/\/\/.*$/).map { |p| p.gsub('////', '').strip } | ||
page_dir_names = page_names.map { |p| "#{p}.playgroundpage" } | ||
|
||
split_file = swift.split(/\/\/\/\/.*$/) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
page_contents = split_file.drop(1).map { |p| p.strip } | ||
preamble = split_file.first.strip | ||
|
||
{ | ||
page_dir_names: page_dir_names, | ||
page_names: page_names, | ||
page_contents: page_contents, | ||
preamble: preamble, | ||
} | ||
end | ||
|
||
def write_chapter_manifest!(chapter_name, page_dir_names) | ||
manifest_contents = { | ||
'Name' => chapter_name, | ||
'Pages' => page_dir_names, | ||
'Version' => '1.0', | ||
'ContentVersion' => '1.0', | ||
} | ||
File.open(ManifestFileName, 'w') do |file| | ||
file.write(manifest_contents.to_plist) | ||
end | ||
end | ||
|
||
def write_preamble!(preamble) | ||
Dir.mkdir(SharedSourcesDirectoryName) unless Dir.exist?(SharedSourcesDirectoryName) | ||
|
||
Dir.chdir(SharedSourcesDirectoryName) do | ||
File.open(PreambleFileName, 'w') do |file| | ||
file.write(preamble) | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
experessions