kitabu 1.0.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -3
- data/.travis.yml +18 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +67 -50
- data/README.md +235 -0
- data/attachments/browser-version.png +0 -0
- data/attachments/cover.png +0 -0
- data/attachments/kitabu.epub +0 -0
- data/attachments/kitabu.mobi +0 -0
- data/attachments/kitabu.pdf +0 -0
- data/{spec/support/mybook/output → examples/kitabu/output/epub/images}/.gitkeep +0 -0
- data/examples/kitabu/output/epub/images/kitabu-icon.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu-icon.svg +19 -0
- data/examples/kitabu/output/epub/images/kitabu-word.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu-word.svg +14 -0
- data/examples/kitabu/output/epub/images/kitabu.png +0 -0
- data/examples/kitabu/output/epub/images/kitabu.svg +20 -0
- data/examples/kitabu/output/epub/section_0.html +266 -0
- data/examples/kitabu/output/epub/section_1.html +246 -0
- data/examples/kitabu/output/epub/section_2.html +520 -0
- data/examples/kitabu/output/epub/section_3.html +282 -0
- data/examples/kitabu/output/epub/section_4.html +276 -0
- data/examples/kitabu/output/epub/styles/epub.css +437 -0
- data/examples/kitabu/output/epub/styles/html.css +712 -0
- data/examples/kitabu/output/epub/styles/pdf.css +840 -0
- data/examples/kitabu/output/epub/styles/print.css +1278 -0
- data/examples/kitabu/output/epub/toc.html +37 -0
- data/{spec/support/mybook/templates/epub/style.css → examples/kitabu/output/images/.gitkeep} +0 -0
- data/examples/kitabu/output/images/kitabu-icon.png +0 -0
- data/examples/kitabu/output/images/kitabu-icon.svg +19 -0
- data/examples/kitabu/output/images/kitabu-word.png +0 -0
- data/examples/kitabu/output/images/kitabu-word.svg +14 -0
- data/examples/kitabu/output/images/kitabu.png +0 -0
- data/examples/kitabu/output/images/kitabu.svg +20 -0
- data/examples/kitabu/output/kitabu.epub +0 -0
- data/examples/kitabu/output/kitabu.html +513 -0
- data/examples/kitabu/output/kitabu.mobi +0 -0
- data/examples/kitabu/output/kitabu.pdf +0 -0
- data/examples/kitabu/output/kitabu.pdf.html +729 -0
- data/examples/kitabu/output/kitabu.print.html +729 -0
- data/examples/kitabu/output/kitabu.print.pdf +0 -0
- data/examples/kitabu/output/kitabu.txt +440 -0
- data/examples/kitabu/output/styles/epub.css +437 -0
- data/examples/kitabu/output/styles/html.css +712 -0
- data/examples/kitabu/output/styles/pdf.css +840 -0
- data/examples/kitabu/output/styles/print.css +1278 -0
- data/kitabu.gemspec +7 -5
- data/lib/kitabu.rb +10 -20
- data/lib/kitabu/cli.rb +0 -5
- data/lib/kitabu/dependency.rb +0 -4
- data/lib/kitabu/exporter.rb +2 -0
- data/lib/kitabu/extensions/rouge.rb +9 -0
- data/lib/kitabu/generator.rb +9 -21
- data/lib/kitabu/helpers.rb +47 -0
- data/lib/kitabu/markdown.rb +31 -0
- data/lib/kitabu/parser.rb +21 -3
- data/lib/kitabu/parser/epub.rb +31 -18
- data/lib/kitabu/parser/html.rb +48 -29
- data/lib/kitabu/parser/mobi.rb +1 -1
- data/lib/kitabu/parser/pdf.rb +52 -8
- data/lib/kitabu/version.rb +2 -2
- data/spec/kitabu/cli/export_spec.rb +4 -4
- data/spec/kitabu/cli/new_spec.rb +2 -2
- data/spec/kitabu/markdown_spec.rb +24 -0
- data/spec/kitabu/parser/html_spec.rb +20 -25
- data/spec/kitabu/parser/mobi_spec.rb +14 -0
- data/spec/kitabu/parser/pdf_spec.rb +18 -1
- data/spec/kitabu/parser/txt_spec.rb +14 -0
- data/spec/spec_helper.rb +10 -6
- data/spec/support/mybook/config/helper.rb +4 -29
- data/spec/support/mybook/config/kitabu.yml +0 -10
- data/spec/support/mybook/templates/epub/cover.erb +4 -3
- data/{templates → spec/support/mybook/templates/epub}/cover.png +0 -0
- data/spec/support/mybook/templates/epub/page.erb +3 -2
- data/spec/support/mybook/templates/html/layout.erb +10 -13
- data/spec/support/mybook/templates/styles/epub.scss +3 -0
- data/spec/support/mybook/templates/styles/html.scss +3 -0
- data/spec/support/mybook/templates/styles/pdf.scss +3 -0
- data/spec/support/mybook/templates/styles/print.scss +3 -0
- data/spec/support/mybook/text/{01_Markdown_Chapter.markdown → 01_Markdown_Chapter.md} +2 -3
- data/spec/support/mybook/text/02_ERB_Chapter.md.erb +7 -0
- data/spec/support/mybook/text/{04_With_Directory/Some_Chapter.mkdn → 03_With_Directory/Some_Chapter.md} +0 -0
- data/spec/support/mybook/text/{CHANGELOG.textile → CHANGELOG.md} +2 -2
- data/spec/support/mybook/text/{TOC.textile → TOC.md} +0 -0
- data/spec/support/mybook/text/{_00_Introduction.markdown → _00_Introduction.md} +0 -0
- data/spec/support/shared.rb +14 -10
- data/templates/Gemfile +3 -3
- data/templates/Guardfile +1 -5
- data/templates/config.erb +5 -5
- data/templates/cover.erb +4 -3
- data/templates/epub.erb +3 -2
- data/templates/helper.rb +28 -29
- data/templates/images/.gitkeep +0 -0
- data/templates/images/kitabu-icon.png +0 -0
- data/templates/images/kitabu-icon.svg +19 -0
- data/templates/images/kitabu-word.png +0 -0
- data/templates/images/kitabu-word.svg +14 -0
- data/templates/images/kitabu.png +0 -0
- data/templates/images/kitabu.svg +20 -0
- data/{examples/RailsGuides/templates → templates/templates/epub}/cover.erb +4 -3
- data/templates/templates/epub/cover.png +0 -0
- data/templates/templates/epub/page.erb +16 -0
- data/templates/{layout.erb → templates/html/layout.erb} +22 -11
- data/templates/templates/styles/epub.scss +1 -0
- data/templates/templates/styles/files/_normalize.scss +427 -0
- data/templates/templates/styles/html.scss +252 -0
- data/templates/templates/styles/pdf.scss +371 -0
- data/templates/templates/styles/print.scss +2 -0
- data/templates/text/01_Getting_Started.md +26 -0
- data/templates/text/02_Creating_Chapters.md +22 -0
- data/templates/text/03_Syntax_Highlighting.erb +69 -0
- data/templates/text/04_Dynamic_Content.erb +64 -0
- data/templates/text/05_Exporting_Files.md +49 -0
- metadata +143 -83
- data/README.rdoc +0 -218
- data/examples/RailsGuides/config/helper.rb +0 -29
- data/examples/RailsGuides/config/kitabu.yml +0 -44
- data/examples/RailsGuides/images/challenge.png +0 -0
- data/examples/RailsGuides/images/posts_index.png +0 -0
- data/examples/RailsGuides/images/rails_welcome.png +0 -0
- data/examples/RailsGuides/output/RailsGuides.epub +0 -0
- data/examples/RailsGuides/output/RailsGuides.html +0 -1556
- data/examples/RailsGuides/output/RailsGuides.pdf +3 -4934
- data/examples/RailsGuides/templates/layout.css +0 -352
- data/examples/RailsGuides/templates/layout.erb +0 -43
- data/examples/RailsGuides/templates/syntax.css +0 -62
- data/examples/RailsGuides/templates/user.css +0 -19
- data/examples/RailsGuides/text/01_Guide_Assumptions.mkdn +0 -13
- data/examples/RailsGuides/text/02_What_is_Rails.mkdn +0 -106
- data/examples/RailsGuides/text/03_Creating_a_new_Rails_project.mkdn +0 -200
- data/examples/RailsGuides/text/04_Hello_Rails.mkdn +0 -62
- data/examples/RailsGuides/text/05_Getting_Up_and_Running_Quickly_with_Scaffolding.mkdn +0 -4
- data/examples/RailsGuides/text/06_Creating_a_resource.mkdn +0 -503
- data/examples/RailsGuides/text/07_Adding_a_second_model.mkdn +0 -232
- data/examples/RailsGuides/text/08_Refactoring.mkdn +0 -123
- data/examples/RailsGuides/text/09_Deleting_comments.mkdn +0 -57
- data/examples/RailsGuides/text/09_Security.mkdn +0 -56
- data/examples/RailsGuides/text/10_Building_a_multi_model_form.mkdn +0 -130
- data/examples/RailsGuides/text/11_View_helpers.mkdn +0 -50
- data/examples/RailsGuides/text/12_Whats_next.mkdn +0 -14
- data/examples/RailsGuides/text/13_Configuration_gotchas.mkdn +0 -10
- data/lib/kitabu/adapters/markdown.rb +0 -34
- data/lib/kitabu/extensions/redcloth.rb +0 -69
- data/lib/kitabu/syntax.rb +0 -130
- data/spec/kitabu/extensions/redcloth_spec.rb +0 -57
- data/spec/kitabu/syntax_spec.rb +0 -106
- data/spec/support/mybook/templates/html/layout.css +0 -353
- data/spec/support/mybook/templates/html/syntax.css +0 -58
- data/spec/support/mybook/templates/html/user.css +0 -1
- data/spec/support/mybook/text/02_Textile_Chapter.textile +0 -3
- data/spec/support/mybook/text/03_HTML_Chapter.html +0 -3
- data/templates/epub.css +0 -500
- data/templates/layout.css +0 -353
- data/templates/sample.md +0 -6
- data/templates/syntax.css +0 -58
- data/templates/user.css +0 -1
@@ -1,130 +0,0 @@
|
|
1
|
-
## Building a Multi-Model Form
|
2
|
-
|
3
|
-
Another feature of your average blog is the ability to tag posts. To implement this feature your application needs to interact with more than one model on a single form. Rails offers support for nested forms.
|
4
|
-
|
5
|
-
To demonstrate this, we will add support for giving each post multiple tags, right in the form where you create the post. First, create a new model to hold the tags:
|
6
|
-
|
7
|
-
$ rails generate model tag name:string post:references
|
8
|
-
|
9
|
-
Again, run the migration to create the database table:
|
10
|
-
|
11
|
-
$ rake db:migrate
|
12
|
-
|
13
|
-
Next, edit the `post.rb` file to create the other side of the association, and to tell Rails (via the `accepts_nested_attributes_for` macro) that you intend to edit tags via posts:
|
14
|
-
|
15
|
-
@@@ ruby
|
16
|
-
class Post < ActiveRecord::Base
|
17
|
-
validates :name, :presence => true
|
18
|
-
validates :title, :presence => true,
|
19
|
-
:length => { :minimum => 5 }
|
20
|
-
|
21
|
-
has_many :comments, :dependent => :destroy
|
22
|
-
has_many :tags
|
23
|
-
|
24
|
-
accepts_nested_attributes_for :tags, :allow_destroy => :true,
|
25
|
-
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
|
26
|
-
end
|
27
|
-
@@@
|
28
|
-
|
29
|
-
The `:allow_destroy` option on the nested attribute declaration tells Rails to display a “remove” checkbox on the view that you’ll build shortly. The `:reject_if` option prevents saving new tags that do not have any attributes filled in.
|
30
|
-
|
31
|
-
We will modify `views/posts/_form.html.erb` to render a partial to make a tag:
|
32
|
-
|
33
|
-
@@@ html
|
34
|
-
<% @post.tags.build %>
|
35
|
-
<%= form_for(@post) do |post_form| %>
|
36
|
-
<% if @post.errors.any? %>
|
37
|
-
<div id="errorExplanation">
|
38
|
-
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
|
39
|
-
<ul>
|
40
|
-
<% @post.errors.full_messages.each do |msg| %>
|
41
|
-
<li><%= msg %></li>
|
42
|
-
<% end %>
|
43
|
-
</ul>
|
44
|
-
</div>
|
45
|
-
<% end %>
|
46
|
-
|
47
|
-
<div class="field">
|
48
|
-
<%= post_form.label :name %><br />
|
49
|
-
<%= post_form.text_field :name %>
|
50
|
-
</div>
|
51
|
-
<div class="field">
|
52
|
-
<%= post_form.label :title %><br />
|
53
|
-
<%= post_form.text_field :title %>
|
54
|
-
</div>
|
55
|
-
<div class="field">
|
56
|
-
<%= post_form.label :content %><br />
|
57
|
-
<%= post_form.text_area :content %>
|
58
|
-
</div>
|
59
|
-
<h2>Tags</h2>
|
60
|
-
<%= render :partial => 'tags/form',
|
61
|
-
:locals => {:form => post_form} %>
|
62
|
-
<div class="actions">
|
63
|
-
<%= post_form.submit %>
|
64
|
-
</div>
|
65
|
-
<% end %>
|
66
|
-
@@@
|
67
|
-
|
68
|
-
Note that we have changed the `f in form_for(@post) do |f|` to `post_form` to make it easier to understand what is going on.
|
69
|
-
|
70
|
-
This example shows another option of the render helper, being able to pass in local variables, in this case, we want the local variable `form` in the partial to refer to the `post_form` object.
|
71
|
-
|
72
|
-
We also add a `@post.tags.build` at the top of this form, this is to make sure there is a new tag ready to have it’s name filled in by the user. If you do not build the new tag, then the form will not appear as there is no new Tag object ready to create.
|
73
|
-
|
74
|
-
Now create the folder `app/views/tags` and make a file in there called `_form.html.erb` which contains the form for the tag:
|
75
|
-
|
76
|
-
@@@ html
|
77
|
-
<%= form.fields_for :tags do |tag_form| %>
|
78
|
-
<div class="field">
|
79
|
-
<%= tag_form.label :name, 'Tag:' %>
|
80
|
-
<%= tag_form.text_field :name %>
|
81
|
-
</div>
|
82
|
-
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
|
83
|
-
<div class="field">
|
84
|
-
<%= tag_form.label :_destroy, 'Remove:' %>
|
85
|
-
<%= tag_form.check_box :_destroy %>
|
86
|
-
</div>
|
87
|
-
<% end %>
|
88
|
-
<% end %>
|
89
|
-
@@@
|
90
|
-
|
91
|
-
Finally, we will edit the `app/views/posts/show.html.erb` template to show our tags.
|
92
|
-
|
93
|
-
@@@ html
|
94
|
-
<p class="notice"><%= notice %></p>
|
95
|
-
|
96
|
-
<p>
|
97
|
-
<b>Name:</b>
|
98
|
-
<%= @post.name %>
|
99
|
-
</p>
|
100
|
-
|
101
|
-
<p>
|
102
|
-
<b>Title:</b>
|
103
|
-
<%= @post.title %>
|
104
|
-
</p>
|
105
|
-
|
106
|
-
<p>
|
107
|
-
<b>Content:</b>
|
108
|
-
<%= @post.content %>
|
109
|
-
</p>
|
110
|
-
|
111
|
-
<p>
|
112
|
-
<b>Tags:</b>
|
113
|
-
<%= @post.tags.map { |t| t.name }.join(", ") %>
|
114
|
-
</p>
|
115
|
-
|
116
|
-
<h2>Comments</h2>
|
117
|
-
<%= render :partial => "comments/comment",
|
118
|
-
:collection => @post.comments %>
|
119
|
-
|
120
|
-
<h2>Add a comment:</h2>
|
121
|
-
<%= render "comments/form" %>
|
122
|
-
|
123
|
-
|
124
|
-
<%= link_to 'Edit Post', edit_post_path(@post) %> |
|
125
|
-
<%= link_to 'Back to Posts', posts_path %> |
|
126
|
-
@@@
|
127
|
-
|
128
|
-
With these changes in place, you’ll find that you can edit a post and its tags directly on the same view.
|
129
|
-
|
130
|
-
However, that method call `@post.tags.map { |t| t.name }.join(", ")` is awkward, we could handle this by making a helper method.
|
@@ -1,50 +0,0 @@
|
|
1
|
-
## View Helpers
|
2
|
-
|
3
|
-
View Helpers live in `app/helpers` and provide small snippets of reusable code for views. In our case, we want a method that strings a bunch of objects together using their name attribute and joining them with a comma. As this is for the Post show template, we put it in the `PostsHelper`.
|
4
|
-
|
5
|
-
Open up `app/helpers/posts_helper.rb` and add the following:
|
6
|
-
|
7
|
-
@@@ ruby
|
8
|
-
module PostsHelper
|
9
|
-
def join_tags(post)
|
10
|
-
post.tags.map { |t| t.name }.join(", ")
|
11
|
-
end
|
12
|
-
end
|
13
|
-
@@@
|
14
|
-
|
15
|
-
Now you can edit the view in `app/views/posts/show.html.erb` to look like this:
|
16
|
-
|
17
|
-
@@@ html
|
18
|
-
<p class="notice"><%= notice %></p>
|
19
|
-
|
20
|
-
<p>
|
21
|
-
<b>Name:</b>
|
22
|
-
<%= @post.name %>
|
23
|
-
</p>
|
24
|
-
|
25
|
-
<p>
|
26
|
-
<b>Title:</b>
|
27
|
-
<%= @post.title %>
|
28
|
-
</p>
|
29
|
-
|
30
|
-
<p>
|
31
|
-
<b>Content:</b>
|
32
|
-
<%= @post.content %>
|
33
|
-
</p>
|
34
|
-
|
35
|
-
<p>
|
36
|
-
<b>Tags:</b>
|
37
|
-
<%= join_tags(@post) %>
|
38
|
-
</p>
|
39
|
-
|
40
|
-
<h2>Comments</h2>
|
41
|
-
<%= render :partial => "comments/comment",
|
42
|
-
:collection => @post.comments %>
|
43
|
-
|
44
|
-
<h2>Add a comment:</h2>
|
45
|
-
<%= render "comments/form" %>
|
46
|
-
|
47
|
-
|
48
|
-
<%= link_to 'Edit Post', edit_post_path(@post) %> |
|
49
|
-
<%= link_to 'Back to Posts', posts_path %> |
|
50
|
-
@@@
|
@@ -1,14 +0,0 @@
|
|
1
|
-
## What’s Next?
|
2
|
-
|
3
|
-
Now that you’ve seen your first Rails application, you should feel free to update it and experiment on your own. But you don’t have to do everything without help. As you need assistance getting up and running with Rails, feel free to consult these support resources:
|
4
|
-
|
5
|
-
* The [Ruby on Rails guides](http://guides.rubyonrails.org/index.html)
|
6
|
-
* The [Ruby on Rails Tutorial](http://railstutorial.org/book)
|
7
|
-
* The [Ruby on Rails mailing list](http://groups.google.com/group/rubyonrails-talk)
|
8
|
-
* The [#rubyonrails](irc://irc.freenode.net/#rubyonrails) channel on irc.freenode.net
|
9
|
-
* The [Rails Wiki](http://wiki.rubyonrails.org/)
|
10
|
-
|
11
|
-
Rails also comes with built-in help that you can generate using the rake command-line utility:
|
12
|
-
|
13
|
-
* Running `rake doc:guides` will put a full copy of the Rails Guides in the `doc/guides` folder of your application. Open `doc/guides/index.html` in your web browser to explore the Guides.
|
14
|
-
* Running `rake doc:rails` will put a full copy of the API documentation for Rails in the `doc/api` folder of your application. Open `doc/api/index.html` in your web browser to explore the API documentation.
|
@@ -1,10 +0,0 @@
|
|
1
|
-
## Configuration Gotchas
|
2
|
-
|
3
|
-
The easiest way to work with Rails is to store all external data as UTF-8. If you don’t, Ruby libraries and Rails will often be able to convert your native data into UTF-8, but this doesn’t always work reliably, so you’re better off ensuring that all external data is UTF-8.
|
4
|
-
|
5
|
-
If you have made a mistake in this area, the most common symptom is a black diamond with a question mark inside appearing in the browser. Another common symptom is characters like “ü” appearing instead of “ü”. Rails takes a number of internal steps to mitigate common causes of these problems that can be automatically detected and corrected. However, if you have external data that is not stored as UTF-8, it can occasionally result in these kinds of issues that cannot be automatically detected by Rails and corrected.
|
6
|
-
|
7
|
-
Two very common sources of data that are not UTF-8:
|
8
|
-
|
9
|
-
* Your text editor: Most text editors (such as Textmate), default to saving files as UTF-8. If your text editor does not, this can result in special characters that you enter in your templates (such as é) to appear as a diamond with a question mark inside in the browser. This also applies to your I18N translation files. Most editors that do not already default to UTF-8 (such as some versions of Dreamweaver) offer a way to change the default to UTF-8. Do so.
|
10
|
-
* Your database. Rails defaults to converting data from your database into UTF-8 at the boundary. However, if your database is not using UTF-8 internally, it may not be able to store all characters that your users enter. For instance, if your database is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese character, the data will be lost forever once it enters the database. If possible, use UTF-8 as the internal storage of your database.
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Kitabu
|
2
|
-
class Markdown
|
3
|
-
# Supported Markdown libraries
|
4
|
-
#
|
5
|
-
MARKDOWN_LIBRARIES = %w[Maruku BlueCloth PEGMarkdown Redcarpet RDiscount]
|
6
|
-
|
7
|
-
# Retrieve preferred Markdown processor.
|
8
|
-
# You'll need one of the following libraries:
|
9
|
-
#
|
10
|
-
# # RDiscount: https://rubygems.org/gems/rdiscount
|
11
|
-
# # Maruku: https://rubygems.org/gems/maruku
|
12
|
-
# # PEGMarkdown: https://rubygems.org/gems/rpeg-markdown
|
13
|
-
# # BlueCloth: https://rubygems.org/gems/bluecloth
|
14
|
-
# # Redcarpet: https://rubygems.org/gems/redcarpet
|
15
|
-
#
|
16
|
-
# Note: RDiscount will always be installed as Kitabu's dependency but only used when no
|
17
|
-
# alternative library is available.
|
18
|
-
#
|
19
|
-
def self.engine
|
20
|
-
@engine ||= Object.const_get(MARKDOWN_LIBRARIES.find {|lib| Object.const_defined?(lib)})
|
21
|
-
end
|
22
|
-
|
23
|
-
# Convert Markdown to HTML.
|
24
|
-
def self.to_html(content)
|
25
|
-
case engine.name
|
26
|
-
when "Redcarpet"
|
27
|
-
render = Redcarpet::Render::HTML.new(:hard_wrap => true, :xhtml => true)
|
28
|
-
Redcarpet::Markdown.new(render).render(content)
|
29
|
-
else
|
30
|
-
engine.new(content).to_html
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
module RedCloth
|
2
|
-
INLINE_FORMATTERS = [:textile, :footnote, :link]
|
3
|
-
|
4
|
-
def self.convert(text)
|
5
|
-
new(text).to_html(*INLINE_FORMATTERS)
|
6
|
-
end
|
7
|
-
|
8
|
-
module Inline
|
9
|
-
FN_RE = /
|
10
|
-
(\s+)? # getting spaces
|
11
|
-
(\\)?%\{ # opening
|
12
|
-
(.*?) # footnote
|
13
|
-
\}# # closing
|
14
|
-
/xm
|
15
|
-
|
16
|
-
def footnote(text)
|
17
|
-
text.gsub!(FN_RE) do |m|
|
18
|
-
if $2
|
19
|
-
%[#{$1}%{#{$3}}]
|
20
|
-
else
|
21
|
-
%(<span class="footnote">#{$3}</span>)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
LINK_RE = /
|
27
|
-
<
|
28
|
-
((?:https?|ftp):\/\/.*?)
|
29
|
-
>
|
30
|
-
/xm
|
31
|
-
|
32
|
-
def link(text)
|
33
|
-
text.gsub!(LINK_RE) do |m|
|
34
|
-
%(<a href="#{$1}">#{$1}</a>)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
module Formatters
|
40
|
-
module HTML
|
41
|
-
def figure(options = {})
|
42
|
-
%[<p class="figure"><img src="../images/#{options[:text]}" alt="#{options[:class]}" /><br/><span class="caption">#{options[:class]}</span></p>]
|
43
|
-
end
|
44
|
-
|
45
|
-
def note(options = {})
|
46
|
-
%[<p class="note">#{options[:text]}</p>]
|
47
|
-
end
|
48
|
-
|
49
|
-
def attention(options = {})
|
50
|
-
%[<p class="attention">#{options[:text]}</p>]
|
51
|
-
end
|
52
|
-
|
53
|
-
def file(options = {})
|
54
|
-
base_url = Kitabu.config[:base_url]
|
55
|
-
|
56
|
-
if base_url
|
57
|
-
url = File.join(base_url, options[:text])
|
58
|
-
else
|
59
|
-
url = content
|
60
|
-
$stderr << "\nYou're using `file. #{content}` but didn't set base_url in your configuration file.\n"
|
61
|
-
end
|
62
|
-
|
63
|
-
%[<p class="file"><span><strong>Download</strong> <a href="#{url}">#{options[:text]}</a></span></p>]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
RedCloth.send(:include, RedCloth::Inline)
|
data/lib/kitabu/syntax.rb
DELETED
@@ -1,130 +0,0 @@
|
|
1
|
-
module Kitabu
|
2
|
-
class Syntax
|
3
|
-
autoload :Highlight, "kitabu/syntax/highlight"
|
4
|
-
|
5
|
-
attr_reader :io
|
6
|
-
attr_reader :lines
|
7
|
-
attr_reader :root_dir
|
8
|
-
attr_reader :format
|
9
|
-
|
10
|
-
# Render syntax blocks from specified source code.
|
11
|
-
#
|
12
|
-
# dir = Pathname.new(File.dirname(__FILE__))
|
13
|
-
# text = File.read(dir.join("text/some_file.textile"))
|
14
|
-
# Kitabu::Syntax.render(dir, :textile, text)
|
15
|
-
#
|
16
|
-
def self.render(root_dir, format, source_code, raw = false)
|
17
|
-
source_code.gsub(/@@@(.*?)@@@/m) do |match|
|
18
|
-
new(root_dir, format, $1, raw).process
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Process each syntax block individually.
|
23
|
-
#
|
24
|
-
def initialize(root_dir, format, code, raw = false)
|
25
|
-
@format = format
|
26
|
-
@root_dir = root_dir
|
27
|
-
@io = StringIO.new(code)
|
28
|
-
@lines = io.readlines.collect(&:chomp)
|
29
|
-
@language = 'text' if raw
|
30
|
-
end
|
31
|
-
|
32
|
-
# Return unprocessed line codes.
|
33
|
-
#
|
34
|
-
def raw
|
35
|
-
lines[1..-1].join("\n")
|
36
|
-
end
|
37
|
-
|
38
|
-
# Return meta data from syntax annotation.
|
39
|
-
#
|
40
|
-
def meta
|
41
|
-
@meta ||= begin
|
42
|
-
line = lines.first.squish
|
43
|
-
_, language, file, modifier, reference = *line.match(/^([^ ]+)(?: ([^:#]+)(?:(:|#)(.*?))?)?$/)
|
44
|
-
|
45
|
-
if modifier == "#"
|
46
|
-
type = :block
|
47
|
-
elsif modifier == ":"
|
48
|
-
type = :range
|
49
|
-
elsif file
|
50
|
-
type = :file
|
51
|
-
else
|
52
|
-
type = :inline
|
53
|
-
end
|
54
|
-
|
55
|
-
{
|
56
|
-
:language => language,
|
57
|
-
:file => file,
|
58
|
-
:type => type,
|
59
|
-
:reference => reference
|
60
|
-
}
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Process syntax block, returning a +pre+ HTML tag.
|
65
|
-
#
|
66
|
-
def process
|
67
|
-
code = raw.to_s.strip_heredoc
|
68
|
-
code = process_file.gsub(/\n^.*?@(begin|end):.*?$/, "") if meta[:file]
|
69
|
-
|
70
|
-
code = Highlight.apply(code, language)
|
71
|
-
|
72
|
-
# escape for textile
|
73
|
-
code = %[<notextile>#{code}</notextile>] if format == :textile
|
74
|
-
code
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
# Process line range as in <tt>@@@ ruby some_file.rb:15,20 @@@</tt>.
|
79
|
-
#
|
80
|
-
def process_range(code)
|
81
|
-
starts, ends = meta[:reference].split(",").collect(&:to_i)
|
82
|
-
code = StringIO.new(code).readlines[starts-1..ends-1].join("\n").strip_heredoc.chomp
|
83
|
-
end
|
84
|
-
|
85
|
-
# Process block name as in <tt>@@@ ruby some_file.rb#some_block @@@</tt>.
|
86
|
-
#
|
87
|
-
def process_block(code)
|
88
|
-
code.gsub!(/\r\n/, "\n")
|
89
|
-
re = %r[@begin: *\b(#{meta[:reference]})\b *[^\n]*\n(.*?)\n[^\n]*@end: \1]im
|
90
|
-
|
91
|
-
if code.match(re)
|
92
|
-
$2.strip_heredoc
|
93
|
-
else
|
94
|
-
"[missing '#{meta[:reference]}' block name]"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Process file and its relatives.
|
99
|
-
#
|
100
|
-
def process_file
|
101
|
-
file_path = root_dir.join("code/#{meta[:file]}")
|
102
|
-
|
103
|
-
if File.exist?(file_path)
|
104
|
-
code = File.read(file_path)
|
105
|
-
|
106
|
-
if meta[:type] == :range
|
107
|
-
process_range(code)
|
108
|
-
elsif meta[:type] == :block
|
109
|
-
process_block(code)
|
110
|
-
else
|
111
|
-
code
|
112
|
-
end
|
113
|
-
else
|
114
|
-
"[missing 'code/#{meta[:file]}' file]"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Return e-book's configuration.
|
119
|
-
#
|
120
|
-
def config
|
121
|
-
Kitabu.config(root_dir)
|
122
|
-
end
|
123
|
-
|
124
|
-
# Return the language used for this syntax block. Overrideable
|
125
|
-
# for epub generation.
|
126
|
-
def language
|
127
|
-
@language || meta[:language]
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe RedCloth do
|
4
|
-
describe "#figure" do
|
5
|
-
it "renders html" do
|
6
|
-
html = RedCloth.convert("figure(The Rails logo). rails.png")
|
7
|
-
expect(html).to have_tag("p.figure") do |p|
|
8
|
-
expect(p).to have_tag("img[@src='../images/rails.png'][@alt='The Rails logo']")
|
9
|
-
expect(p).to have_tag("span.caption", "The Rails logo")
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#note" do
|
15
|
-
it "renders html" do
|
16
|
-
html = RedCloth.convert("note. Some important note!")
|
17
|
-
expect(html).to have_tag("p.note", "Some important note!")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#attention" do
|
22
|
-
it "renders html" do
|
23
|
-
html = RedCloth.convert("attention. Some warning note!")
|
24
|
-
expect(html).to have_tag("p.attention", "Some warning note!")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "#file" do
|
29
|
-
it "renders html" do
|
30
|
-
allow(Kitabu).to receive_message_chain(:config).and_return(base_url: "http://example.com")
|
31
|
-
html = RedCloth.convert("file. app/models/users.rb")
|
32
|
-
|
33
|
-
expect(html).to have_tag("p.file") do |p|
|
34
|
-
expect(p).to have_tag("a[@href='http://example.com/app/models/users.rb']", "app/models/users.rb")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context "custom footnote helper" do
|
40
|
-
it "renders html" do
|
41
|
-
html = RedCloth.convert("Writing some text with a footnote %{this is a footnote}")
|
42
|
-
expect(html).to eq(%[<p>Writing some text with a footnote<span class="footnote">this is a footnote</span></p>])
|
43
|
-
end
|
44
|
-
|
45
|
-
it "ignores escaped notations" do
|
46
|
-
html = RedCloth.convert("It must skip \\%{this}")
|
47
|
-
expect(html).to eq(%[<p>It must skip %{this}</p>])
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context "custom url helper" do
|
52
|
-
it "renders html" do
|
53
|
-
html = RedCloth.convert("<http://example.com>")
|
54
|
-
expect(html).to eq(%[<p><a href="http://example.com">http://example.com</a></p>])
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|