mint 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +437 -0
- data/bin/mint +42 -0
- data/lib/mint.rb +433 -0
- data/templates/default/layout.haml +7 -0
- data/templates/default/style.sass +21 -0
- metadata +72 -0
data/README.md
ADDED
@@ -0,0 +1,437 @@
|
|
1
|
+
*The following is a **rough draft** of the current Mint design, along with my future plans for the library and tool.*
|
2
|
+
|
3
|
+
Possible taglines
|
4
|
+
-----------------
|
5
|
+
|
6
|
+
I don't actually believe in tag lines, but if Mint were to have one, it might be one of these:
|
7
|
+
|
8
|
+
- Value your words. Leave the formatting up to us.
|
9
|
+
- Reuse your ideas. Reuse your formats. Keep them Mint fresh.
|
10
|
+
- Mint once, remix as needed.
|
11
|
+
|
12
|
+
Introduction
|
13
|
+
------------
|
14
|
+
|
15
|
+
Mint is an agile, lightweight solution for your documents.
|
16
|
+
|
17
|
+
Mint manages your documents in a decentralized way. It frees you from bloated word processors. Mint brings together standards and common templating languages for a clean, agile approach to documents. It uses HTML outside of the web. Leverages text for tons of different views. Keeps your data and formatting separate. In a word: simplifies. In a couple of words: kicks ass.
|
18
|
+
|
19
|
+
In a few more: *Mint processes words so you don't have to.*
|
20
|
+
|
21
|
+
Table of contents
|
22
|
+
-----------------
|
23
|
+
|
24
|
+
I. Use cases
|
25
|
+
II. The Mint library
|
26
|
+
III. Designing a template
|
27
|
+
IV. The Mint path
|
28
|
+
V. The `mint` command
|
29
|
+
VI. Future directions and tools
|
30
|
+
|
31
|
+
I. Use cases
|
32
|
+
------------
|
33
|
+
|
34
|
+
1. Jake has text files formatted as Markdown-style text. He has traditionally published these as blog entries, which works well because his webserver takes care of processing the Markdown, generating HTML, and styling it with his static CSS. Jake has no way of visualizing his documents without a webserver running. He likes the convenience of centralized CSS styles that he can update once and cascade everywhere. He does not like depending on a webserver for static pages. Jake wants a document management system where source files are written in Markdown but are "printed" into HTML and styled with centralized sheets he creates himself.
|
35
|
+
|
36
|
+
2. Donna has traditionally used a WYSIWYG word processor to create, edit, version, and present ideas in her personal and school life (not work). She wants her documents to exist forever without breaking standards: she wants them to be completely future-compatible. Therefore, she wants to migrate away from her proprietary word processor. She wants a migration tool to make the initial conversion. Interoperability with other people is not required. As long as she can view and print formatted documents, keeping source files as plaintext, she is happy.
|
37
|
+
|
38
|
+
3. Bertrande wants to build a styles gallery that previews certain styles on Textile-formatted documents using a web application... (finish later)
|
39
|
+
|
40
|
+
4. Marina wants to convert all her proprietary processed documents to Markdown for future compatibility, but wants to share these documents with friends at work. Interoperability is important here. The friends should be able to easily view *and* edit *and* annotate all documents.
|
41
|
+
|
42
|
+
II. The Mint library
|
43
|
+
--------------------
|
44
|
+
|
45
|
+
This section discusses the Mint library API. Read on for the mint binary.
|
46
|
+
|
47
|
+
### A basic Mint document ###
|
48
|
+
|
49
|
+
Mint is loaded with smart defaults, so if you don't want to configure something--say, the basic HTML skeleton of your document or the output name or director--you don't have to. You'll probably be surprised at how easy it is to use out of the box, and how configurable it is.
|
50
|
+
|
51
|
+
document = Document.new '~/Documents/Minimalism.md'
|
52
|
+
document.press
|
53
|
+
|
54
|
+
And voilà, you will find the following next to Minimalism.md in the same directory:
|
55
|
+
|
56
|
+
- Minimalism.html
|
57
|
+
- styles/default.css
|
58
|
+
|
59
|
+
Opening Minimalism.html with your favorite web browser--[Firefox is best for typography][Firefox typography]--will show what looks like a word processed document, complete with big bolded headers, italic emphasis, automatically numbered lists, and bullets.
|
60
|
+
|
61
|
+
Sending that page to a printer is as easy as clicking "Print" from your browser. What comes out of your printer will have a 12 pt base font, normal margins, and a not-too-cramped baseline. (Ah the wonder of print stylesheets.)
|
62
|
+
|
63
|
+
If you want to customize your document, though--and that's why I built this library--Mint makes that easy.
|
64
|
+
|
65
|
+
[Firefox typography]: http://opentype.info/blog/2008/06/14/kerning-and-opentype-features-in-firefox-3/ "Firefox 3 supports kerning and automatic ligatures"
|
66
|
+
|
67
|
+
### Customizing Mint ###
|
68
|
+
|
69
|
+
To understand how the library works, with and without configuration, it is helpful to look at the options you can pass to the library and what their defaults are.
|
70
|
+
|
71
|
+
You can pass any of the following to a new document:
|
72
|
+
|
73
|
+
- `:layout` and `:style` are names of templates or file names.
|
74
|
+
|
75
|
+
Defaults:
|
76
|
+
|
77
|
+
:layout => 'default'
|
78
|
+
:style => 'default'
|
79
|
+
|
80
|
+
Notes:
|
81
|
+
|
82
|
+
1. If you specify a template name here, Mint will search its paths in order (see **The Mint Path** for more details) for a template with that name. A template file looks like the following:
|
83
|
+
|
84
|
+
PATH/templates/TEMPLATE_NAME/style.sass
|
85
|
+
PATH/templates/TEMPLATE_NAME/layout.haml
|
86
|
+
|
87
|
+
2. If you specify a template name, it MUST be a simple name without extensions or directories included. Also, it must not be the name of a file in the working directory. (It is unlikely you'll have an extension-less file named 'normal' or 'default' in your working directory.)
|
88
|
+
|
89
|
+
3. You can include path information if you're specifying a source file instead of a template name. If you do specify a file, the path/file will be resolved from the directory where you're calling Mint (the 'working directory'). If you're going to use Mint this way (and I don't see this as more than a temporary solution) you'll probably want to call Mint from the context of your source directory. Alternatively, you can use [`Dir.chdir`][Dir::chdir method] for the same effect.
|
90
|
+
|
91
|
+
4. You can specify nil if you don't want a style to be rendered. This is useful if you're pointing a lot of documents to one stylesheet and only want to Mint the stylesheet one time.
|
92
|
+
|
93
|
+
- `:root` is the root context of the final document. That is, the output. All relative *output* paths are resolved from the root path. `:root` itself must be an absolute path or nil. In most cases where you want a relative `:root`, try using `:destination`, instead. `:root` is most useful when compiling several source documents from different folders into a single, centralized directory.
|
94
|
+
|
95
|
+
Default:
|
96
|
+
|
97
|
+
:root => nil
|
98
|
+
|
99
|
+
Notes:
|
100
|
+
|
101
|
+
1. If nil, `:root` defaults to your content's parent directory.
|
102
|
+
2. `:root` MUST be a directory.
|
103
|
+
|
104
|
+
- `:destination` lets you specify a subdirectory for your output. There is an option to specify a separate `:style_destination`. The former is resolved relative to `:root`. The latter is resolved relative to `:destination`.
|
105
|
+
|
106
|
+
Defaults:
|
107
|
+
|
108
|
+
:destination => nil
|
109
|
+
:style_destination => nil
|
110
|
+
|
111
|
+
Notes:
|
112
|
+
|
113
|
+
1. `:destination` MUST refer to a directory and *not* a file. If you want to specify the output file name, use the `:name` parameter.
|
114
|
+
|
115
|
+
2. Mint resolves `:destination` relative to `:root` and serves as a way of organizing output files. `:style_destination` is resolved relative to `:destination` so that packaging styles inside document directories is easy. (This supports the common case where you will want a subdirectory called `'styles'` to hold your style files.)
|
116
|
+
|
117
|
+
3. If either value is nil, it is simply ignored.
|
118
|
+
|
119
|
+
- `:name` is the name of the output file, which will end up in `/:root/:destination/`. `:style_name` is the name of the stylesheet output file and will show up in `/:root/:destination/:style_destination/`.
|
120
|
+
|
121
|
+
Defaults:
|
122
|
+
|
123
|
+
:name => nil
|
124
|
+
:style_name => nil
|
125
|
+
|
126
|
+
Notes:
|
127
|
+
|
128
|
+
1. If nil, the name of a Document or stylesheet comes from it's source file. (Minimalism.md will turn into Minimalism.html without configuration.)
|
129
|
+
|
130
|
+
In summary: if `:root` is unspecified, it will be the directory where your content file. The rendered content and style files will be placed directly into this directory unless given a specific `:destination`. The output names will come from their source files unless you specify `:name`.
|
131
|
+
|
132
|
+
Without configuration, `destination = root = content.dirname.expand_path`
|
133
|
+
|
134
|
+
### Examples ###
|
135
|
+
|
136
|
+
At this point, a couple of example may be useful.
|
137
|
+
|
138
|
+
The following are possible:
|
139
|
+
|
140
|
+
content = '~/Documents/Minimalism.md'
|
141
|
+
|
142
|
+
Document.new content
|
143
|
+
|
144
|
+
Document.new content, :root => '~/Documents/Final', :destination => 'directory', :name => 'final.html'
|
145
|
+
Document.new content, :root => 'directory'
|
146
|
+
Document.new content, :root => 'directory', :destination => 'subdirectory'
|
147
|
+
|
148
|
+
Style.new 'normal'
|
149
|
+
Style.new '~/Sites/Commons/style/normal.sass', :destination => 'style', :name => 'normal.css' # :destination is converted to :style_destination in the context of a document
|
150
|
+
Style.new '~/Sites/Commons/style/normal.css'
|
151
|
+
Style.new 'Commons/style/normal.css'
|
152
|
+
|
153
|
+
If block-style initiation is your thing:
|
154
|
+
|
155
|
+
Document.new content do |d|
|
156
|
+
d.root = 'my-book'
|
157
|
+
d.name = 'my-book-final-draft.html'
|
158
|
+
|
159
|
+
d.style 'normal' do |s|
|
160
|
+
s.destination = 'styles'
|
161
|
+
s.name = 'stylesheet.css'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
> Note: Block-style indentation passes the block to you after initializing
|
166
|
+
> the Document with default values. So you do not need to worry about
|
167
|
+
> specifying each argument. Anything you specify will override what is already there.
|
168
|
+
|
169
|
+
[Dir::chdir method]: http://ruby-doc.org/core/classes/Dir.html#M002314 "You can change the current directory context with Dir::chdir(path)"
|
170
|
+
|
171
|
+
III. Designing a template
|
172
|
+
-------------------------
|
173
|
+
|
174
|
+
Templates can be written in any format accepted by the Tilt template interface library. (See [the Tilt TEMPLATES file][Tilt templates] for more information.)
|
175
|
+
|
176
|
+
Mint gives you convenience methods that you can use in your templates.
|
177
|
+
|
178
|
+
### Place your content, point to your styles ###
|
179
|
+
|
180
|
+
If you're designing a layout, you need to indicate where Mint should place your content. Therefore, raw HTML files cannot be layouts. Instead, if you want to use HTML templates, you should change the extension to .erb. These files are essentially HTML with the possibility for Ruby calls.
|
181
|
+
|
182
|
+
Inside your template, use the keyword (well, actually the method) `content` to place your source's content.
|
183
|
+
|
184
|
+
You will want to point to your document's stylesheet (via a relative URL) from within your layout, usually in the `<head/>` element. Use the keyword `stylesheet`.
|
185
|
+
|
186
|
+
So if you're writing your layout using Erb, the template might look like this:
|
187
|
+
|
188
|
+
<!doctype html>
|
189
|
+
<html>
|
190
|
+
<head>
|
191
|
+
<link rel='stylesheet' href='<%= stylesheet %>' />
|
192
|
+
</head>
|
193
|
+
|
194
|
+
<body>
|
195
|
+
<div id='container'>
|
196
|
+
<%= content %>
|
197
|
+
</div>
|
198
|
+
</body>
|
199
|
+
</html>
|
200
|
+
|
201
|
+
The same layout in Haml would be:
|
202
|
+
|
203
|
+
!!!
|
204
|
+
%html
|
205
|
+
%head
|
206
|
+
%link{ :rel => 'stylesheet', :href => stylesheet }
|
207
|
+
|
208
|
+
%body
|
209
|
+
#container= content
|
210
|
+
|
211
|
+
### Style your content ###
|
212
|
+
|
213
|
+
You can build stylesheets using [CSS][], [Sass/Scss][] or [Less][].
|
214
|
+
|
215
|
+
[Tilt templates]: http://github.com/rtomayko/tilt/blob/master/TEMPLATES.md "A listing of all templates supported by Tilt."
|
216
|
+
[CSS]: http://en.wikipedia.org/wiki/Cascading_Style_Sheets
|
217
|
+
[Sass/Scss]: http://sass-lang.com/
|
218
|
+
[Less]: http://lesscss.org/
|
219
|
+
|
220
|
+
Mint comes preloaded with several styles and layouts:
|
221
|
+
|
222
|
+
1. Default
|
223
|
+
2. Serif Pro
|
224
|
+
3. Sans Pro
|
225
|
+
4. Protocol
|
226
|
+
5. Protocol Flow - requires Javascript
|
227
|
+
6. Resume
|
228
|
+
|
229
|
+
IV. The Mint path
|
230
|
+
-----------------
|
231
|
+
|
232
|
+
Mint's path can be useful for a lot of things, especially for extensions and tools that use the library. The most important use for the path in the library is to find named templates.
|
233
|
+
|
234
|
+
When given a style or layout name (instead of a file name), Mint will search its paths in order until it finds the appropriate template. If no template is found, it will fall back to the default template.
|
235
|
+
|
236
|
+
The default Mint path (in order) is:
|
237
|
+
|
238
|
+
- the current working directory
|
239
|
+
- HOME_DIRECTORY/.mint
|
240
|
+
- /usr/share/mint (or whatever your system uses for system-wide configuration)
|
241
|
+
- the gem's source directory (as a final effort)
|
242
|
+
|
243
|
+
Templates should be in a directory named templates. Inside this directory, there should be a subdirectory for each template:
|
244
|
+
|
245
|
+
- PATH/templates/normal/style.sass
|
246
|
+
- PATH/templates/normal/layout.haml
|
247
|
+
|
248
|
+
Normally a style will go best with its complement layout. However, layouts and styles can be mixed and matched at your discretion. This is especially true where you are not using stylesheets to format specific IDs or classes you're expecting to find in your layout. (In other words, this works best when you're focused on typography and not page layout.)
|
249
|
+
|
250
|
+
V. The `mint` command
|
251
|
+
---------------------
|
252
|
+
|
253
|
+
### The basic `mint` command ###
|
254
|
+
|
255
|
+
The easiest Mint command doesn't require configuration. It will transform all of your Documents into HTML and link all of them to the default stylesheet, which will be output in the same directory as the source documents.
|
256
|
+
|
257
|
+
mint
|
258
|
+
|
259
|
+
If you have a ./templates/default/ subdirectory, the templates found in that directory will be used.
|
260
|
+
|
261
|
+
This command can be tweaked with options and arguments to be more flexible:
|
262
|
+
|
263
|
+
mint Minimalism.md # renders a specific file
|
264
|
+
mint Minimalism.md Final.html # specifies an output file
|
265
|
+
mint Minimalism.md --style=resume # specifies a style template
|
266
|
+
mint Minimalism.md --root=~/Documents/Minimalism --style=default --style-destination=styles
|
267
|
+
|
268
|
+
### Mint options & shortcuts ###
|
269
|
+
|
270
|
+
You can pass several options to `mint`. Each option has a short form.
|
271
|
+
|
272
|
+
The following correspond to the parameters you can pass to `Mint::Document.new`, as described in [The Mint library][]:
|
273
|
+
|
274
|
+
- `--layout, -L`
|
275
|
+
- `--style, -S`
|
276
|
+
- `--root, -R`
|
277
|
+
- `--destination, -D`
|
278
|
+
- `--name, -N`
|
279
|
+
- `--style-destination`
|
280
|
+
- `--style-name`
|
281
|
+
|
282
|
+
Other options have nothing to do with document configuration but are there for convenience:
|
283
|
+
|
284
|
+
- `--verbose, -v` - will output all rendering results
|
285
|
+
- `--simulation, -s` - will not actually render any files
|
286
|
+
|
287
|
+
[The Mint library]: #ii_the_mint_library
|
288
|
+
|
289
|
+
### Mint projects ###
|
290
|
+
|
291
|
+
A more powerful and reconfigurable version of Mint uses Mint projects. To initialize a project in the current directory:
|
292
|
+
|
293
|
+
mint init
|
294
|
+
|
295
|
+
The following does the same thing, but all documents rendered in this project will use the normal template (both layout and style) by default.
|
296
|
+
|
297
|
+
mint init --template normal
|
298
|
+
|
299
|
+
The following does the same thing, but all documents rendered in this project will use the protocol.haml layout and serif-professional style by default.
|
300
|
+
|
301
|
+
mint init --layout protocol.haml --style serif-professional
|
302
|
+
|
303
|
+
You will want to make sure that your layouts and styles are compatible. Most text-heavy layouts should be compatible with any style (and Mint is made for text-heavy documents). If you're using Mint with specialized style files, though, and expect certain IDs and classes in your layout document, you will want to check for layout/style compatibility.
|
304
|
+
|
305
|
+
A project stores references to all of its documents. You can list documents with:
|
306
|
+
|
307
|
+
mint list
|
308
|
+
|
309
|
+
You can find out which documents have been minted (and where), along with any universal templates using:
|
310
|
+
|
311
|
+
mint status
|
312
|
+
|
313
|
+
### Project configuration ###
|
314
|
+
|
315
|
+
Mint projects can be associated with [Yaml configuration files][Yaml]. These files are created if you pass any options to `mint init` when you create a project. Alternatively, you can set global configuration options after creating a project:
|
316
|
+
|
317
|
+
mint set --template serif-pro
|
318
|
+
|
319
|
+
Projects use configuration files *and not command-line options* to determine how they should behave. You can modify the config file through the command line, but do not use the command line to pass options while minting an entire project.
|
320
|
+
|
321
|
+
In other words, this is okay for minting a single file:
|
322
|
+
|
323
|
+
mint --template normal
|
324
|
+
|
325
|
+
It is *not* okay if you are inside a project. In this case, you SHOULD alter the configuration file (via command line or an editor) and then type:
|
326
|
+
|
327
|
+
mint
|
328
|
+
|
329
|
+
The config.yaml file can include the following options:
|
330
|
+
|
331
|
+
layout: normal
|
332
|
+
destination: output
|
333
|
+
style: normal
|
334
|
+
style_destination: styles
|
335
|
+
template: resume # overrides layout and style options
|
336
|
+
|
337
|
+
[...]
|
338
|
+
|
339
|
+
These files give you the power to unify a project with a certain layout and style.
|
340
|
+
|
341
|
+
If configuration options get complicated, it may be useful to list all active defaults:
|
342
|
+
|
343
|
+
mint config
|
344
|
+
|
345
|
+
[Yaml]: http://yaml.org/
|
346
|
+
|
347
|
+
### Editing files in a project ###
|
348
|
+
|
349
|
+
Inside of a project directory, you can edit any stylesheet or document template that would normally be used by the project without delving into the Mint templates directories.
|
350
|
+
|
351
|
+
mint edit --layout default # selects the first template in your path
|
352
|
+
mint edit --style normal # with the appropriate name
|
353
|
+
|
354
|
+
Mint will open the appropriate file in the editor specified by EDITOR. There is a short form for each option:
|
355
|
+
|
356
|
+
mint edit -L normal
|
357
|
+
mint edit -S normal
|
358
|
+
|
359
|
+
To remove all mint-generated files in a directory (or for a package):
|
360
|
+
|
361
|
+
mint restore .
|
362
|
+
|
363
|
+
VI. The future of Mint
|
364
|
+
----------------------
|
365
|
+
|
366
|
+
This section documents features that do not yet exist, but that I would like to have in future versions of Mint.
|
367
|
+
|
368
|
+
### Possible next steps ###
|
369
|
+
|
370
|
+
I might introduce the concept of a project registry. This would allow for interlinking between Mint projects scattered around a system, or perhaps even remotely. (How useful would a remote link be without the Web, though?)
|
371
|
+
|
372
|
+
`mint init` would register a project, whose name would be based on its parent directory. The project directory would be a user-wide listing that could allow hyperlinking between separate Mint projects, along with use of common stylesheets. There would also be a manual option:
|
373
|
+
|
374
|
+
mint add --project ~/Projects/NamedProject --name=NamedProject
|
375
|
+
|
376
|
+
### Packages ###
|
377
|
+
|
378
|
+
Sometimes, it may be useful to "finalize" the design of a document, for example, with publications. The best way I can think of to do this is to package the document's output file along with its style in a zipped package, which can be read by the following:
|
379
|
+
|
380
|
+
mint open --package Minimalism --in firefox
|
381
|
+
|
382
|
+
To package a document with its stylesheet, as a sort of a printing:
|
383
|
+
|
384
|
+
mint package document.md --name Document # will get the extension .pkg?
|
385
|
+
|
386
|
+
Eventually, I want this to include multiple output formats, like HTML4, HTML5, PDF and ePub. The format opened by the `mint open` command could be determined by the application you choose to open it with.
|
387
|
+
|
388
|
+
When that does happen, you'll also be able to set the default version of the document that will open using:
|
389
|
+
|
390
|
+
mint set --package-default html5
|
391
|
+
|
392
|
+
### My dreams about Mint, and where it could go ###
|
393
|
+
|
394
|
+
I have more ideas for Mint, but they are probably far-off pipe dreams.
|
395
|
+
|
396
|
+
What if Mint were social and a good citizen with respect to data portability? This could look like:
|
397
|
+
|
398
|
+
mint share --user http://davejacobs.myopenid.com/
|
399
|
+
mint share --user =david --service freeXRI
|
400
|
+
mint share --user @dave_jacobs --service twitter
|
401
|
+
mint share --service twitter
|
402
|
+
|
403
|
+
For this last command, Mint would upload an HTML to a preconfigured FTP server or web application and then post a link to that document in the recipient's Twitter stream. I'm not sure exactly how this would go.
|
404
|
+
|
405
|
+
The configuration file could look something like:
|
406
|
+
|
407
|
+
services:
|
408
|
+
- twitter:
|
409
|
+
authorization: OAuth
|
410
|
+
key: etc.
|
411
|
+
|
412
|
+
- openid:
|
413
|
+
url: http://davejacobs.myopenid.com/
|
414
|
+
authorization: OAuth
|
415
|
+
key: etc.
|
416
|
+
|
417
|
+
Or you could publish multiple output formats, and to multiple locations:
|
418
|
+
|
419
|
+
mint publish --ftp default
|
420
|
+
mint publish --blog personal
|
421
|
+
|
422
|
+
The configuration:
|
423
|
+
|
424
|
+
publishers:
|
425
|
+
- ftp:
|
426
|
+
- default:
|
427
|
+
server: ftp.provider.com
|
428
|
+
security: sftp
|
429
|
+
directory: /home/USERNAME/example.com/documents
|
430
|
+
- blog:
|
431
|
+
- personal:
|
432
|
+
|
433
|
+
Or you could connect to a service to protect your intellectual property rights:
|
434
|
+
|
435
|
+
mint copyright
|
436
|
+
|
437
|
+
I don't know if this is even possible, but wouldn't it be cool to generate a unique number based on the date, time, and contents of any article published and assign it to the article as a hash of all its metadata. The number would be so complex that you could not generate it without all the appropriate data. And using all the appropriate metadata (including date) would give the same number every time. But somehow, the algorithm would have to never run after the current date, so that potential plagiarists could not figure out what the hash should be for a date previous to the date you published it. That idea needs work, but I feel like maybe it could work out, probably as a separate service. Wouldn't it be cool?
|
data/bin/mint
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# A script for harnessing Mint at the commandline
|
3
|
+
|
4
|
+
$:.unshift File.join(File.dirname(File.readlink(__FILE__)), '..', 'lib')
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'mint'
|
8
|
+
require 'optparse'
|
9
|
+
|
10
|
+
def usage
|
11
|
+
puts "You're doing it wrong."
|
12
|
+
end
|
13
|
+
|
14
|
+
unless ARGV[0]
|
15
|
+
usage
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
19
|
+
include Mint
|
20
|
+
|
21
|
+
module CommandLine
|
22
|
+
module DocumentContext
|
23
|
+
def mint_document(doc)
|
24
|
+
document = Document.new doc, :template => 'normal',
|
25
|
+
:style_destination => 'styles'
|
26
|
+
document.mint
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module ProjectContext
|
31
|
+
def init(dir, opts={})
|
32
|
+
dir = Pathname.new dir
|
33
|
+
if config = (dir + 'config.yaml').exists?
|
34
|
+
proj = Project.new(dir, YAML.load_file(config))
|
35
|
+
else
|
36
|
+
proj = Project.new(dir)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
CommandLine::DocumentContext.mint_document ARGV[0]
|
data/lib/mint.rb
ADDED
@@ -0,0 +1,433 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tilt'
|
4
|
+
require 'haml'
|
5
|
+
require 'rdiscount'
|
6
|
+
|
7
|
+
require 'helpers'
|
8
|
+
|
9
|
+
module Mint
|
10
|
+
VERSION = '0.1'
|
11
|
+
|
12
|
+
# Default paths where Mint looks for styles and layouts, in this order
|
13
|
+
$path = [
|
14
|
+
Pathname.new('.mint'), # 1. Project-defined
|
15
|
+
Pathname.new(ENV['HOME']) + '.mint', # 2. User-defined
|
16
|
+
Pathname.new('/usr') + 'share' + 'mint', # 3. System-defined
|
17
|
+
Pathname.new(__FILE__).dirname + '..' # 4. Gemfile-defined
|
18
|
+
].collect! {|p| p.expand_path }
|
19
|
+
|
20
|
+
# Directories within the Mint path
|
21
|
+
$default_directories = {
|
22
|
+
:templates => 'templates'
|
23
|
+
}
|
24
|
+
|
25
|
+
# Files within a Mint Project
|
26
|
+
$default_files = {
|
27
|
+
:config => 'config.yaml'
|
28
|
+
}
|
29
|
+
|
30
|
+
# Registered HTML and CSS formats, for source -> destination
|
31
|
+
# name guessing/conversion
|
32
|
+
$html_formats = ['.haml', '.erb', '.md']
|
33
|
+
$css_formats = ['.sass', '.scss', '.less']
|
34
|
+
$source_formats = $html_formats + $css_formats
|
35
|
+
|
36
|
+
# Default options, where nil acts as described in the specification
|
37
|
+
# Namely, a nil root or destination or style/layout template will
|
38
|
+
# not be used, and a nil name will prompt Mint to guess an appropriate
|
39
|
+
# name based on your source files
|
40
|
+
$default_opts = {
|
41
|
+
:template => 'default', # this is a new feature I need to test
|
42
|
+
# :layout => 'default',
|
43
|
+
# :style => 'default',
|
44
|
+
:root => nil,
|
45
|
+
:destination => nil,
|
46
|
+
:style_destination => nil,
|
47
|
+
:name => nil,
|
48
|
+
:style_name => nil
|
49
|
+
}
|
50
|
+
|
51
|
+
class Resource
|
52
|
+
attr_accessor :type, :source, :destination, :name
|
53
|
+
|
54
|
+
def initialize(source, opts={}, &block)
|
55
|
+
# A nil stylesheet or layout should not be rendered, so
|
56
|
+
# we'll return nil here
|
57
|
+
return nil unless source
|
58
|
+
|
59
|
+
# If there is a source, we initialize it right away as a
|
60
|
+
# Pathname, so we can use methods like @source.basename
|
61
|
+
@source = Pathname.new source
|
62
|
+
|
63
|
+
# Load in opts and change nil values to the assumptions
|
64
|
+
# described in the Mint README.
|
65
|
+
@opts = opts
|
66
|
+
|
67
|
+
# If there is no destination value, ignore it
|
68
|
+
@opts[:destination] ||= String.new
|
69
|
+
|
70
|
+
# For a nil name, guess based on source
|
71
|
+
@opts[:name] ||= Resource.guess_from(@source.basename.to_s)
|
72
|
+
|
73
|
+
# Initialize resource values based on normalized, robust
|
74
|
+
# opts. For raw resources (i.e., not for Documents), the destination
|
75
|
+
# and source are both resolved relative to the current working
|
76
|
+
# directory. This only really matters if you are initializing Layouts
|
77
|
+
# or Styles on your own instead of via a Document. If you're using
|
78
|
+
# a Document, all destination paths are resolved relative to the
|
79
|
+
# Document root, which defaults to the content's source directory.
|
80
|
+
@destination = Pathname.new @opts[:destination]
|
81
|
+
@name = @opts[:name]
|
82
|
+
@template = Resource.template @source
|
83
|
+
|
84
|
+
# You can use a block to instantiate a Resource. Any values you set
|
85
|
+
# in this block will override all other values.
|
86
|
+
if block_given?
|
87
|
+
yield self
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def equals?(other)
|
92
|
+
destination + name == other.destination + other.name
|
93
|
+
end
|
94
|
+
|
95
|
+
alias_method :==, :equals?
|
96
|
+
|
97
|
+
# A convenience method for supplying and selecting configuration
|
98
|
+
# options. If supplied with an array of possible values, will return
|
99
|
+
# the first non-nil value. If the first non-nil value responds to
|
100
|
+
# `call`, will call that function and return its value.
|
101
|
+
def config_with(config)
|
102
|
+
(c = config.compact[0]).respond_to?(:call) ? c.call : c
|
103
|
+
end
|
104
|
+
|
105
|
+
# Renders the current resource to a string, returning that string
|
106
|
+
# and not outputting to any file. Can operate within the context of
|
107
|
+
# an Object, whose methods can be called from within the template.
|
108
|
+
# Other arguments can be passed along to the template compiler. (For
|
109
|
+
# example, to output HAML as HTML5, pass the option `:format =>
|
110
|
+
# :html5`. See the Tilt TEMPLATES.md file for more information.)
|
111
|
+
def render(context=Object.new, args={})
|
112
|
+
@template.render context, args
|
113
|
+
end
|
114
|
+
|
115
|
+
# Guesses an appropriate name for the Resource output file based on
|
116
|
+
# its source file's base name. Will convert registered HTML template
|
117
|
+
# extensions to '.html' and CSS template extensions to '.css'.
|
118
|
+
def self.guess_from(name)
|
119
|
+
css, html = $css_formats.join('|'), $html_formats.join('|')
|
120
|
+
name.gsub(/#{css}/, '.css').gsub(/#{html}/, '.html')
|
121
|
+
end
|
122
|
+
|
123
|
+
# Transforms a path into a template that will render the file specified
|
124
|
+
# at that path. Currently uses Tilt, so any valid Tilt source file
|
125
|
+
# is valid here.
|
126
|
+
def self.template(path)
|
127
|
+
Tilt.new path
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Layout describes a resource whose type is `:layout`. Beyond its type,
|
132
|
+
# it is a simple resource. However, its type helps decide which template
|
133
|
+
# file to use when a template name is specified. A Layout is best managed
|
134
|
+
# by a Document.
|
135
|
+
class Layout < Resource
|
136
|
+
def initialize(source, args={})
|
137
|
+
@type = :layout
|
138
|
+
super
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Style describes a resource whose type is `:style`. Beyond its type,
|
143
|
+
# it is a simple resource. However, its type helps decide which template
|
144
|
+
# file to use when a template name is specified. A Style is best managed
|
145
|
+
# by a Document.
|
146
|
+
class Style < Resource
|
147
|
+
def initialize(source, args={})
|
148
|
+
@type = :style
|
149
|
+
super
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Document is a workhorse of the Mint library. It extends Resource
|
154
|
+
# to include helpful variables like `root`, which will be the context
|
155
|
+
# for all the Resources it contains. A Document's source is its content
|
156
|
+
# file, from which it can derive a root directory, an output name, and
|
157
|
+
# destination directories. A Document has one Style and one Layout, which
|
158
|
+
# it initializes on creation. Default and optional Styles and Layouts are
|
159
|
+
# included with Mint. You can add more templates to the Mint path
|
160
|
+
# for even more choices.
|
161
|
+
class Document < Resource
|
162
|
+
attr_accessor :root, :layout, :style, :content
|
163
|
+
|
164
|
+
def initialize(source, opts={}, &block)
|
165
|
+
# Initialize opts to the default opts, replacing them with user-
|
166
|
+
# supplied opts where possible.
|
167
|
+
@opts = $default_opts.merge opts
|
168
|
+
|
169
|
+
# Invoke the parent class initializer, which sets the source,
|
170
|
+
# destination, name, template (content), and basic options.
|
171
|
+
super(source, @opts)
|
172
|
+
|
173
|
+
# Add in Doc-specific opts and change nil values to the
|
174
|
+
# assumptions described in the Mint README.
|
175
|
+
@opts[:root] ||= @source.dirname
|
176
|
+
|
177
|
+
# If a template name is given, it overrides style and layout
|
178
|
+
# names or files, per the Mint README.
|
179
|
+
if templ = @opts[:template]
|
180
|
+
@opts[:layout], @opts[:style] = templ, templ
|
181
|
+
end
|
182
|
+
|
183
|
+
@opts[:style_destination] ||= String.new
|
184
|
+
|
185
|
+
style_opts = {
|
186
|
+
:destination => @destination + @opts[:style_destination],
|
187
|
+
:name => @opts[:style_name]
|
188
|
+
}
|
189
|
+
|
190
|
+
# Initialize resource values based on normalized, robust opts. For
|
191
|
+
# Documents, the destination is resolved relative to the document
|
192
|
+
# root. The root and source paths are both resolved relative to the
|
193
|
+
# current working directory whenever this instantiation method
|
194
|
+
# is called.
|
195
|
+
@type = :document
|
196
|
+
@root = Pathname.new(@opts[:root]).expand_path
|
197
|
+
|
198
|
+
@content = Resource.template(@source).render
|
199
|
+
@layout = choose_template(@opts[:layout], :layout)
|
200
|
+
@style = choose_template(@opts[:style], :style, style_opts)
|
201
|
+
|
202
|
+
# Be careful not to modify this code such that you can change the
|
203
|
+
# current working directory before the source directory is normalized.
|
204
|
+
# expand_path is always called relative to the *current* working
|
205
|
+
# directory, not the initial one.
|
206
|
+
@source = normalize_path(@source) # becomes relative here
|
207
|
+
|
208
|
+
# You can use a block to instantiate a Document. Any values you set
|
209
|
+
# in this block will override all other values.
|
210
|
+
if block_given?
|
211
|
+
yield self
|
212
|
+
mint
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns the relative path to dir1 from dir2, which defaults to the
|
217
|
+
# Document root.
|
218
|
+
def normalize_path(dir1, dir2=root)
|
219
|
+
Document.normalize_path(dir1, dir2)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Returns the relative path to dir1 from dir2.
|
223
|
+
def self.normalize_path(dir1, dir2)
|
224
|
+
path = case dir1
|
225
|
+
when String
|
226
|
+
Pathname.new dir1
|
227
|
+
when Pathname
|
228
|
+
dir1
|
229
|
+
end
|
230
|
+
|
231
|
+
path.expand_path.relative_path_from dir2
|
232
|
+
end
|
233
|
+
|
234
|
+
# Decides whether the template specified by `name_or_file` is a real
|
235
|
+
# file or the name of a template. If it is a real file, Mint will
|
236
|
+
# return a template using that file. Otherwise, Mint will look for a
|
237
|
+
# template with that name in the Mint path. The `layout_or_style`
|
238
|
+
# argument indicates whether the template we are looking for is
|
239
|
+
# a layout or a style and will affect which type of template is returned
|
240
|
+
# for a given template name. For example, `choose_template('normal',
|
241
|
+
# :layout)` might return a Layout template referring to the file
|
242
|
+
# ~/.mint/templates/normal/layout.haml. Changing the second argument
|
243
|
+
# to :style would return a Style template whose source file is
|
244
|
+
# ~/.mint/templates/normal/style.sass.
|
245
|
+
def choose_template(name_or_file, layout_or_style=:layout, opts={})
|
246
|
+
template = File.file?(name_or_file) ? Pathname.new(name_or_file) :
|
247
|
+
find_template(name_or_file, layout_or_style)
|
248
|
+
|
249
|
+
Mint.const_get(layout_or_style.to_s.capitalize).new(template, opts)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Finds a template named `name` in the Mint path. If `layout_or_style`
|
253
|
+
# is :layout, will look for `MINT_PATH/templates/layout.*`. If it is
|
254
|
+
# :style, will look for `MINT_PATH/templates/TEMPLATE_NAME/style.*`.
|
255
|
+
# Will reject raw HTML and CSS, which are currently not compatible
|
256
|
+
# with Tilt, the rendering interface that Mint uses. (There are plans
|
257
|
+
# to support these files in the future.) Mint assumes that a named
|
258
|
+
# template will hold only one layout and one style template. It does
|
259
|
+
# not know how to decide between style.sass and style.less, for
|
260
|
+
# example. For predictable results, only include one template file
|
261
|
+
# called `layout.*` in the TEMPLATE_NAME directory. If you do want
|
262
|
+
# several style files in the same template directory, you will want
|
263
|
+
# to refer to the style file by its path and not by its template name.
|
264
|
+
# Will return nil if the named template is not in the Mint path.
|
265
|
+
def find_template(name, layout_or_style)
|
266
|
+
file = nil
|
267
|
+
|
268
|
+
$path.each do |directory|
|
269
|
+
templates_dir = directory + $default_directories[:templates]
|
270
|
+
query = templates_dir + name + layout_or_style.to_s
|
271
|
+
|
272
|
+
if templates_dir.exist?
|
273
|
+
# Mint looks for any
|
274
|
+
results = Pathname.glob "#{query}.*"
|
275
|
+
|
276
|
+
# Will only allow files ending in extensions that Tilt can
|
277
|
+
# handle. They are working to add raw HTML and CSS support, but
|
278
|
+
# it is not yet implemented.
|
279
|
+
results.reject {|r| r.to_s !~ /#{$source_formats.join('|')}/}
|
280
|
+
|
281
|
+
if results.length > 0
|
282
|
+
# Will return the first match found. See the `find_template`
|
283
|
+
# description for a discussion of when you should and should
|
284
|
+
# not rely on this method.
|
285
|
+
file = results[0]
|
286
|
+
break
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
file
|
292
|
+
end
|
293
|
+
|
294
|
+
# A Document renders itself (its content) in the context of its layout.
|
295
|
+
# This differs from raw Resources, which render themselves in the
|
296
|
+
# context of `Object.new`
|
297
|
+
def render(args={})
|
298
|
+
layout.render self, args
|
299
|
+
end
|
300
|
+
|
301
|
+
# Renders and writes to file all Resources described by a Document.
|
302
|
+
# Specifically: it renders itself (inside of its own Layout) and then
|
303
|
+
# renders its Style. This method will overwrite any existing content
|
304
|
+
# in a Document's destination files. The `render_style?` option
|
305
|
+
# provides an easy way to stop Mint from rendering a style, even
|
306
|
+
# if the Document's style is not nil. This makes it possible to
|
307
|
+
# associate a style with a Document (a style that can be called
|
308
|
+
# from layouts via `stylesheet`) without regenerating that
|
309
|
+
# stylesheet every time Mint runs.
|
310
|
+
def mint(render_style?=true)
|
311
|
+
|
312
|
+
resources = [self]
|
313
|
+
resources << style if render_style?
|
314
|
+
|
315
|
+
resources.compact.each do |r|
|
316
|
+
dest = @root + r.destination + r.name
|
317
|
+
|
318
|
+
# Kernel.puts <<-HERE
|
319
|
+
# Source: #{@root + r.source}
|
320
|
+
# Destination: #{dest}
|
321
|
+
# HERE
|
322
|
+
|
323
|
+
# Create any directories in the destination path that don't exist.
|
324
|
+
FileUtils.mkdir_p dest.dirname
|
325
|
+
|
326
|
+
# Render the resource to its destination file, overwriting any
|
327
|
+
# existing content.
|
328
|
+
dest.open 'w+' do |file|
|
329
|
+
file << r.render
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# Convenience methods for views
|
335
|
+
|
336
|
+
# Returns a relative path from the Document to its stylesheet. Can
|
337
|
+
# be called directly from inside a Layout template.
|
338
|
+
def stylesheet
|
339
|
+
normalize_path(@root + style.destination,
|
340
|
+
@root + @destination) +
|
341
|
+
style.name.to_s
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
$project_default_opts = {}
|
346
|
+
|
347
|
+
class ProjectDocument < Document
|
348
|
+
attr_accessor :changed?
|
349
|
+
end
|
350
|
+
|
351
|
+
class Project
|
352
|
+
attr_accessor :root, :documents, :layout, :style, :config
|
353
|
+
|
354
|
+
def initialize(root, opts={})
|
355
|
+
@opts = opts
|
356
|
+
@opts = $project_default_opts.merge opts
|
357
|
+
|
358
|
+
if templ = @opts[:template]
|
359
|
+
@opts[:layout], @opts[:style] = templ, templ
|
360
|
+
end
|
361
|
+
|
362
|
+
@root = root
|
363
|
+
@documents = Array.new
|
364
|
+
@style = @opts[:style]
|
365
|
+
@layout = @opts[:layout]
|
366
|
+
end
|
367
|
+
|
368
|
+
def mint
|
369
|
+
@documents.each_index do |i|
|
370
|
+
render_style? = (i == 0)
|
371
|
+
@documents[i].mint(render_style?)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def change_status(document, new_status)
|
376
|
+
end
|
377
|
+
|
378
|
+
def status
|
379
|
+
end
|
380
|
+
|
381
|
+
def add(document)
|
382
|
+
doc = Document.new
|
383
|
+
doc.layout = @layout
|
384
|
+
doc.style = @style
|
385
|
+
doc.root = @root
|
386
|
+
|
387
|
+
@documents << doc
|
388
|
+
end
|
389
|
+
|
390
|
+
alias_method :<<, :add
|
391
|
+
|
392
|
+
def remove(document)
|
393
|
+
@documents.delete document
|
394
|
+
end
|
395
|
+
|
396
|
+
def list
|
397
|
+
end
|
398
|
+
|
399
|
+
def edit(file_or_name, type=:layout)
|
400
|
+
|
401
|
+
|
402
|
+
if editor = ENV['EDITOR']
|
403
|
+
`#{editor} `
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def watch
|
408
|
+
require 'fssm'
|
409
|
+
|
410
|
+
FSSM.monitor do
|
411
|
+
path root do
|
412
|
+
glob '*'
|
413
|
+
|
414
|
+
update {|base, relative|}
|
415
|
+
delete {|base, relative|}
|
416
|
+
create {|base, relative|}
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
path 'templates/**/*' do
|
421
|
+
update { |base, relative| update(relative) }
|
422
|
+
delete { |base, relative| update(relative) }
|
423
|
+
create { |base, relative| update(relative) }
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def update(relative)
|
428
|
+
puts ">>> Change Detected to: #{relative} <<<"
|
429
|
+
|
430
|
+
puts '>>> Update Complete <<<'
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
body
|
2
|
+
font-family: 'Hoefler Text', Georgia, Garamond, serif
|
3
|
+
|
4
|
+
code
|
5
|
+
font-family: Monaco, 'Lucida Console', Consolas, Monotype, mono
|
6
|
+
|
7
|
+
@media screen
|
8
|
+
body
|
9
|
+
font-size: 16px
|
10
|
+
|
11
|
+
#container
|
12
|
+
display: block
|
13
|
+
margin: 1em auto
|
14
|
+
|
15
|
+
@media print
|
16
|
+
body
|
17
|
+
font-size: 12pt
|
18
|
+
margin: 1in 1.25in
|
19
|
+
|
20
|
+
img
|
21
|
+
display: block
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- David Jacobs
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-06-28 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: david@allthingsprogress.com
|
23
|
+
executables:
|
24
|
+
- mint
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- README.md
|
31
|
+
- bin/mint
|
32
|
+
- lib/mint.rb
|
33
|
+
- templates/default/layout.haml
|
34
|
+
- templates/default/style.sass
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/davejacobs/mint/
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
hash: 3
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 23
|
59
|
+
segments:
|
60
|
+
- 1
|
61
|
+
- 3
|
62
|
+
- 6
|
63
|
+
version: 1.3.6
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.7
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Clean, simple library for maintaining and styling documents without a word processor
|
71
|
+
test_files: []
|
72
|
+
|