mint 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 &amp; 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?
@@ -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]
@@ -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,7 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %link{ :rel => 'stylesheet', :href => stylesheet }
5
+
6
+ %body
7
+ #container= content
@@ -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
+