mint 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,31 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'yaml'
4
+
5
+ module Mint
6
+ module Helpers
7
+ # Returns the relative path to dir1 from dir2.
8
+ def self.normalize_path(dir1, dir2)
9
+ path = case dir1
10
+ when String
11
+ Pathname.new dir1
12
+ when Pathname
13
+ dir1
14
+ end
15
+
16
+ path.expand_path.relative_path_from(dir2.expand_path)
17
+ end
18
+
19
+ def self.ensure_directory(dir)
20
+ FileUtils.mkdir_p dir
21
+ end
22
+
23
+ def self.update_yaml(new_opts, file)
24
+ curr_opts = file.exist? ? YAML.load_file(file) : {}
25
+
26
+ File.open file, 'w' do |f|
27
+ YAML.dump curr_opts.merge(new_opts), f
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/mint/mint.rb ADDED
@@ -0,0 +1,309 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'tilt'
4
+ require 'helpers'
5
+
6
+ module Mint
7
+ VERSION = '0.1.3'
8
+ MINT_DIR = Pathname.new(__FILE__).realpath.dirname + '..'
9
+
10
+ # Assume that someone using an Html template has formatted it
11
+ # in Erb and that a Css stylesheet will pass untouched through
12
+ # a Less parser.
13
+ Tilt.register 'html', Tilt::ERBTemplate
14
+ Tilt.register 'css', Tilt::LessTemplate
15
+
16
+ # Return the an array with the Mint template path. Will first look
17
+ # for MINT_PATH environment variable. Otherwise will use smart defaults.
18
+ # Either way, earlier/higher paths take precedence.
19
+ def self.path
20
+ mint_path = ENV['MINT_PATH'] || "#{Dir.getwd}/.mint:~/.mint:#{MINT_DIR}"
21
+ path = mint_path.split(':').map {|p| Pathname.new(p).expand_path }
22
+ end
23
+
24
+ # I want to refactor this so that Mint.path is always a Hash...
25
+ # should take care of this in the Mint.path=() method.
26
+ # Right now, this is a hack. It assumes a sane MINT_PATH, where the
27
+ # first entry is most local and the last entry is most global.
28
+ def self.path_for_scope(scope=:local)
29
+ case Mint.path
30
+ when Array
31
+ index = { local: 0, user: 1, global: 2 }[scope]
32
+ Mint.path[index]
33
+ when Hash
34
+ Mint.path[scope]
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ # Returns a hash with key Mint directories
41
+ def self.directories
42
+ { templates: 'templates' }
43
+ end
44
+
45
+ # Returns a hash with key Mint files
46
+ def self.files
47
+ { config: 'config.yaml' }
48
+ end
49
+
50
+ def self.default_options
51
+ {
52
+ # Do not set default `template`--will override style and
53
+ # layout when already specified -- causes tricky bugs
54
+ layout: 'default', # default layout
55
+ style: 'default', # default style
56
+ destination: nil, # do not create a subdirectory
57
+ style_destination: nil # do not copy style to root
58
+ }
59
+ end
60
+
61
+ # Returns a list of all file extensions that Tilt will render
62
+ def self.formats
63
+ Tilt.mappings.keys
64
+ end
65
+
66
+ # Registered Css formats, for source -> destination
67
+ # name guessing/conversion only.
68
+ def self.css_formats
69
+ css_formats = ['.css', '.sass', '.scss', '.less']
70
+ end
71
+
72
+ # Decides whether the template specified by `name_or_file` is a real
73
+ # file or the name of a template. If it is a real file, Mint will
74
+ # return a that file. Otherwise, Mint will look for a file with that
75
+ # name in the Mint path. The `type` argument indicates whether the
76
+ # template we are looking for is a layout or a style and will affect
77
+ # which type of template is returned for a given template name. For
78
+ # example, `lookup_template :normal` might return a layout template
79
+ # referring to the file ~/.mint/templates/normal/layout.erb.
80
+ # Adding :style as a second argument returns
81
+ # ~/.mint/templates/normal/style.css.
82
+ def self.lookup_template(name_or_file, type=:layout)
83
+ name = name_or_file.to_s
84
+ File.exist?(name) ? Pathname.new(name) : find_template(name, type)
85
+ end
86
+
87
+ # Finds a template named `name` in the Mint path. If `type` # is :layout,
88
+ # will look for `${MINT_PATH}/templates/layout.*`. If it is :style, will
89
+ # look for `${MINT_PATH}/templates/template_name/style.*`. Mint assumes
90
+ # that a named template will hold only one layout and one style template.
91
+ # It does not know how to decide between style.css and style.less, for
92
+ # example. For predictable results, only include one template file
93
+ # called `layout.*` in the `template_name` directory. Returns nil if
94
+ # it cannot find a template.
95
+ def self.find_template(name, type)
96
+ templates_dir = Mint.directories[:templates]
97
+
98
+ file_name = lambda {|x| x + templates_dir + name + type.to_s }
99
+ find_files = lambda {|x| Pathname.glob "#{x.to_s}.*" }
100
+ acceptable = lambda {|x| x.to_s =~ /#{Mint.formats.join '|'}/ }
101
+
102
+ Mint.path.
103
+ map(&file_name).map(&find_files).flatten.
104
+ select(&acceptable).select(&:exist?).
105
+ first
106
+ end
107
+
108
+ # Guesses an appropriate name for the resource output file based on
109
+ # its source file's base name
110
+ def self.guess_name_from(name)
111
+ css = Mint.css_formats.join '|'
112
+ name.basename.to_s.
113
+ gsub(/(#{css})$/, '.css').
114
+ gsub(/(\.[^css]+)$/, '.html')
115
+ end
116
+
117
+ # Transforms a path into a template that will render the file specified
118
+ # at that path
119
+ def self.renderer(path)
120
+ Tilt.new path.to_s, :smart => true
121
+ end
122
+
123
+ class Resource
124
+ attr_accessor :type
125
+
126
+ attr_reader :source
127
+ def source=(source)
128
+ @source = Pathname.new(source) if source
129
+ end
130
+
131
+ # I haven't tested this - moved empty string from
132
+ # default options into this method, so that default options
133
+ # can be uniform - i.e., style_destination and destination
134
+ # can each be nil to indicate that any rendering will be
135
+ # done in the same folder the file is already in. I need
136
+ # to make sure that adding the empty string here actually
137
+ # keeps us in the current working directory
138
+ attr_reader :destination
139
+ def destination=(destination)
140
+ @destination = Pathname.new(destination || '')
141
+ end
142
+
143
+ attr_reader :name
144
+ def name=(name)
145
+ @name = name
146
+ end
147
+
148
+ def renderer=(renderer)
149
+ @renderer = renderer
150
+ end
151
+
152
+ def initialize(source, type=:resource, options={})
153
+ return nil unless source
154
+
155
+ self.source = source
156
+ self.type = type
157
+ self.destination = options[:destination]
158
+ self.name = Mint.guess_name_from source
159
+ self.renderer = Mint.renderer source
160
+ end
161
+
162
+ def equal?(other)
163
+ destination + name == other.destination + other.name
164
+ end
165
+ alias_method :==, :equal?
166
+
167
+ def render(context=Object.new, args={})
168
+ # see Tilt TEMPLATES.md for more info
169
+ @renderer.render context, args
170
+ end
171
+ end
172
+
173
+ # Layout describes a resource whose type is `:layout`. Beyond its type,
174
+ # it is a simple resource. However, its type helps decide which template
175
+ # file to use when a template name is specified.
176
+ class Layout < Resource
177
+ def initialize(source, opts=Mint.default_options)
178
+ super(source, :layout, opts)
179
+ end
180
+ end
181
+
182
+ # Style describes a resource whose type is `:style`. Beyond its type,
183
+ # it is a simple resource. However, its type helps decide which template
184
+ # file to use when a template name is specified.
185
+ class Style < Resource
186
+ def initialize(source, opts=Mint.default_options)
187
+ super(source, :style, opts)
188
+ end
189
+
190
+ def needs_rendering?
191
+ source.extname !~ /\.css$/
192
+ end
193
+ end
194
+
195
+ class Document < Resource
196
+ include Helpers
197
+
198
+ # The following provide reader/accessor methods for the objects's
199
+ # important attributes. Each implicit reader is paired with an
200
+ # explicit assignment method that processes a variety of input to a
201
+ # standardized state.
202
+
203
+ # When you set content, you are giving the document a renderer based
204
+ # on the content file and are processing the templated content into
205
+ # Html, which you can then access using via the content reader.
206
+ attr_reader :content
207
+ def content=(content)
208
+ meta, body = src.split "\n\n"
209
+ @inline_style = YAML.load meta
210
+ @renderer = Mint.renderer body
211
+ @content = @renderer.render
212
+ rescue
213
+ # I want to dry up this part of the code - and maybe look up which
214
+ # error Yaml will throw if it can't parse the first paragraph
215
+ # in the content
216
+ @renderer = Mint.renderer content
217
+ @content = @renderer.render
218
+ end
219
+
220
+ # The explicit assignment method allows you to pass the document an existing
221
+ # layout or the name of a layout template in the Mint path or an
222
+ # existing layout file.
223
+ attr_reader :layout
224
+ def layout=(layout)
225
+ @layout =
226
+ if layout.respond_to? :render
227
+ layout
228
+ else
229
+ layout_file = Mint.lookup_template layout, :layout
230
+ Layout.new layout_file
231
+ end
232
+ end
233
+
234
+ # The explicit assignment method allows you to pass the document an existing
235
+ # style or the name of a style template in the Mint path or an
236
+ # existing style file.
237
+ attr_reader :style
238
+ def style=(style)
239
+ @style =
240
+ if style.respond_to? :render
241
+ style
242
+ else
243
+ style_file = Mint.lookup_template style, :style
244
+ Style.new style_file, :destination => destination
245
+ end
246
+ end
247
+
248
+ def template=(template)
249
+ layout, style = template, template if template
250
+ end
251
+
252
+ def initialize(source, opts={})
253
+ options = Mint.default_options.merge opts
254
+ super(source, :document, options)
255
+
256
+ # Each of these should invoke explicitly defined method
257
+ self.content = source
258
+ self.layout = options[:layout]
259
+ self.style = options[:style]
260
+
261
+ # The template option takes precedence over the other two
262
+ self.template = options[:template]
263
+
264
+ self.style.destination =
265
+ options[:style_destination] || self.style.source.dirname.expand_path
266
+ end
267
+
268
+ def render(args={})
269
+ layout.render self, args
270
+ end
271
+
272
+ def mint(root=Dir.getwd, render_style=true)
273
+ root = Pathname.new root
274
+
275
+ # Only render style if a) it's specified by the options path and
276
+ # b) it actually needs rendering (i.e., it's in template form and
277
+ # not raw, browser-parseable CSS).
278
+ render_style &&= style.needs_rendering?
279
+
280
+ resources = [self]
281
+ resources << style if render_style
282
+
283
+ resources.compact.each do |r|
284
+ dest = root + r.destination + r.name
285
+ FileUtils.mkdir_p dest.dirname
286
+
287
+ dest.open 'w+' do |f|
288
+ f << r.render
289
+ end
290
+ end
291
+ end
292
+
293
+ # Convenience methods for views
294
+
295
+ # Returns any inline document style that was parsed from the
296
+ # content file, in the header. For use in view where we want
297
+ # document-specific Css modifications.
298
+ def inline_style
299
+ @inline_style
300
+ end
301
+
302
+ # Returns a relative path from the document to its stylesheet. Can
303
+ # be called directly from inside a layout template.
304
+ def stylesheet
305
+ Helpers.normalize_path(style.destination.expand_path, destination) +
306
+ style.name.to_s
307
+ end
308
+ end
309
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mint
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
7
  - 1
9
- - 1
10
- version: 0.1.1
8
+ - 3
9
+ version: 0.1.3
11
10
  platform: ruby
12
11
  authors:
13
12
  - David Jacobs
@@ -15,10 +14,22 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-06-28 00:00:00 -04:00
17
+ date: 2011-02-01 00:00:00 -05:00
19
18
  default_executable:
20
- dependencies: []
21
-
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: tilt
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
22
33
  description:
23
34
  email: david@allthingsprogress.com
24
35
  executables:
@@ -31,10 +42,10 @@ files:
31
42
  - README.md
32
43
  - bin/mint
33
44
  - lib/mint.rb
34
- - templates/default/layout.haml
35
- - templates/default/style.sass
45
+ - lib/mint/mint.rb
46
+ - lib/mint/helpers.rb
36
47
  has_rdoc: true
37
- homepage: http://github.com/davejacobs/mint/
48
+ homepage: http://github.com/davejacobs/mint
38
49
  licenses: []
39
50
 
40
51
  post_install_message:
@@ -47,7 +58,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
58
  requirements:
48
59
  - - ">="
49
60
  - !ruby/object:Gem::Version
50
- hash: 3
51
61
  segments:
52
62
  - 0
53
63
  version: "0"
@@ -56,7 +66,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
66
  requirements:
57
67
  - - ">="
58
68
  - !ruby/object:Gem::Version
59
- hash: 23
60
69
  segments:
61
70
  - 1
62
71
  - 3
@@ -1,7 +0,0 @@
1
- !!!
2
- %html
3
- %head
4
- %link{ :rel => 'stylesheet', :href => stylesheet }
5
-
6
- %body
7
- #container= content
@@ -1,21 +0,0 @@
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