mint 0.8.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -26
  3. data/README.md +117 -37
  4. data/bin/mint +2 -81
  5. data/config/templates/base/navigation.css +136 -0
  6. data/config/templates/base/print.css +152 -0
  7. data/config/templates/{reset.css → base/reset.css} +1 -1
  8. data/config/templates/base/style.css +117 -137
  9. data/config/templates/base/utilities.css +136 -0
  10. data/config/templates/base/variables.css +124 -0
  11. data/config/templates/basic/style.css +151 -0
  12. data/config/templates/default/layout.erb +33 -3
  13. data/config/templates/default/style.css +95 -164
  14. data/config/templates/magazine/style.css +383 -0
  15. data/config/templates/nord/style.css +105 -220
  16. data/config/templates/nord-dark/style.css +82 -263
  17. data/lib/mint/commandline/parse.rb +144 -0
  18. data/lib/mint/commandline/publish.rb +46 -0
  19. data/lib/mint/commandline/run.rb +30 -0
  20. data/lib/mint/config.rb +162 -0
  21. data/lib/mint/{css.rb → css_dsl.rb} +9 -9
  22. data/lib/mint/css_parser.rb +45 -25
  23. data/lib/mint/document.rb +250 -365
  24. data/lib/mint/document_tree.rb +163 -0
  25. data/lib/mint/exceptions.rb +2 -3
  26. data/lib/mint/helpers.rb +23 -180
  27. data/lib/mint/layout.rb +26 -9
  28. data/lib/mint/renderers/css_renderer.rb +32 -0
  29. data/lib/mint/renderers/erb_renderer.rb +11 -0
  30. data/lib/mint/renderers/markdown_renderer.rb +45 -0
  31. data/lib/mint/style.rb +21 -31
  32. data/lib/mint/template.rb +30 -0
  33. data/lib/mint/version.rb +1 -1
  34. data/lib/mint/workspace.rb +171 -0
  35. data/lib/mint.rb +44 -12
  36. data/man/mint.1 +85 -44
  37. data/spec/cli/README.md +2 -2
  38. data/spec/cli/argument_parsing_spec.rb +89 -147
  39. data/spec/cli/bin_integration_spec.rb +23 -243
  40. data/spec/cli/full_workflow_integration_spec.rb +99 -442
  41. data/spec/cli/original_style_integration_spec.rb +58 -0
  42. data/spec/cli/publish_workflow_spec.rb +72 -70
  43. data/spec/commandline_path_integration_spec.rb +230 -0
  44. data/spec/config_file_integration_spec.rb +362 -0
  45. data/spec/{css_spec.rb → css_dsl_spec.rb} +7 -3
  46. data/spec/css_parser_spec.rb +59 -1
  47. data/spec/document_spec.rb +37 -242
  48. data/spec/flattened_path_spec.rb +150 -0
  49. data/spec/layout_spec.rb +42 -3
  50. data/spec/mint_spec.rb +22 -217
  51. data/spec/path_handling_spec.rb +237 -0
  52. data/spec/run_cli_tests.rb +1 -1
  53. data/spec/spec_helper.rb +3 -10
  54. data/spec/style_spec.rb +31 -56
  55. data/spec/support/cli_helpers.rb +7 -10
  56. data/spec/support/matchers.rb +1 -1
  57. data/spec/template_spec.rb +31 -0
  58. data/spec/workspace_spec.rb +177 -0
  59. metadata +75 -89
  60. data/bin/mint-epub +0 -20
  61. data/config/templates/garden/layout.erb +0 -38
  62. data/config/templates/garden/style.css +0 -303
  63. data/config/templates/nord/layout.erb +0 -11
  64. data/config/templates/nord-dark/layout.erb +0 -11
  65. data/config/templates/zen/layout.erb +0 -11
  66. data/config/templates/zen/style.css +0 -114
  67. data/lib/mint/command_line.rb +0 -360
  68. data/lib/mint/css_template.rb +0 -37
  69. data/lib/mint/markdown_template.rb +0 -47
  70. data/lib/mint/mint.rb +0 -313
  71. data/lib/mint/plugin.rb +0 -136
  72. data/lib/mint/plugins/epub.rb +0 -293
  73. data/lib/mint/resource.rb +0 -101
  74. data/plugins/templates/epub/layouts/container.haml +0 -5
  75. data/plugins/templates/epub/layouts/content.haml +0 -35
  76. data/plugins/templates/epub/layouts/layout.haml +0 -6
  77. data/plugins/templates/epub/layouts/title.haml +0 -11
  78. data/plugins/templates/epub/layouts/toc.haml +0 -26
  79. data/spec/cli/configuration_management_spec.rb +0 -363
  80. data/spec/cli/template_management_spec.rb +0 -300
  81. data/spec/helpers_spec.rb +0 -249
  82. data/spec/plugin_spec.rb +0 -449
  83. data/spec/resource_spec.rb +0 -135
@@ -0,0 +1,163 @@
1
+ require "pathname"
2
+
3
+ module Mint
4
+ class DocumentTree
5
+ attr_reader :nodes
6
+
7
+ # Initializes a new DocumentTree with the given documents
8
+ #
9
+ # @param [Array<Document>] documents array of documents to add to the tree
10
+ def initialize(documents)
11
+ @nodes = []
12
+ documents.each do |document|
13
+ add_document(document.destination_path, document.title)
14
+ end
15
+ sort_nodes!
16
+ end
17
+
18
+ # Returns new DocumentTree with paths relative to reference_pathname
19
+ # Preserves the tree structure but reorients all paths
20
+ #
21
+ # @param [Pathname] reference_pathname path to the reference pathname
22
+ # @return [DocumentTree] new DocumentTree with paths relative to reference_pathname
23
+ def reorient(reference_pathname)
24
+ reoriented_nodes = reorient_nodes(@nodes, reference_pathname)
25
+ new_tree = DocumentTree.allocate
26
+ new_tree.instance_variable_set(:@nodes, reoriented_nodes)
27
+ new_tree
28
+ end
29
+
30
+ # Serializes the tree to a flat array for ERB template consumption
31
+ #
32
+ # ERB templates cannot easily handle recursive tree structures with arbitrary depth,
33
+ # so we flatten the tree into a simple array of hashes that the template can iterate over.
34
+ # Each hash contains the navigation item data (title, paths, depth) needed for rendering.
35
+ #
36
+ # @param [Integer] max_depth maximum navigation depth (optional)
37
+ # @return [Array<Hash>] flattened array of navigation items
38
+ def serialize(max_depth: nil)
39
+ result = []
40
+ flatten_nodes(@nodes, result, max_depth: max_depth)
41
+ result
42
+ end
43
+
44
+ private
45
+
46
+ def add_document(path, title)
47
+ parts = path.to_s.split('/').reject(&:empty?)
48
+ current_nodes = @nodes
49
+
50
+ parts.each_with_index do |part, idx|
51
+ # Find or create node for this part
52
+ node = current_nodes.find {|n| n.name == part }
53
+
54
+ if node.nil?
55
+ # Create new node
56
+ path_so_far = Pathname.new(parts[0..idx].join('/'))
57
+ is_file = (idx == parts.length - 1)
58
+
59
+ node = DocumentTreeNode.new(
60
+ name: part,
61
+ pathname: path_so_far,
62
+ title: is_file ? title : part,
63
+ depth: idx,
64
+ is_file: is_file
65
+ )
66
+ current_nodes << node
67
+ end
68
+
69
+ current_nodes = node.children
70
+ end
71
+ end
72
+
73
+ def sort_nodes!
74
+ sort_nodes_recursive(@nodes)
75
+ end
76
+
77
+ def sort_nodes_recursive(nodes)
78
+ nodes.sort_by! {|node| [node.directory? ? 0 : 1, node.name] }
79
+ nodes.each {|node| sort_nodes_recursive(node.children) }
80
+ end
81
+
82
+ def reorient_nodes(nodes, reference_pathname)
83
+ nodes.map do |node|
84
+ new_pathname = calculate_relative_path(node.pathname, reference_pathname)
85
+ new_children = reorient_nodes(node.children, reference_pathname)
86
+
87
+ DocumentTreeNode.new(
88
+ name: node.name,
89
+ pathname: new_pathname,
90
+ title: node.title,
91
+ depth: node.depth,
92
+ is_file: node.file?
93
+ ).tap do |new_node|
94
+ new_node.instance_variable_set(:@children, new_children)
95
+ end
96
+ end
97
+ end
98
+
99
+ def flatten_nodes(nodes, result, depth = 0, max_depth: nil)
100
+ return if max_depth && depth >= max_depth
101
+
102
+ nodes.each do |node|
103
+ if node.file?
104
+ result << {
105
+ title: node.title,
106
+ html_path: node.pathname.to_s,
107
+ source_path: node.pathname.to_s,
108
+ depth: depth
109
+ }
110
+ else
111
+ result << {
112
+ title: node.title,
113
+ html_path: nil,
114
+ source_path: nil,
115
+ depth: depth,
116
+ is_directory: true
117
+ }
118
+
119
+ flatten_nodes(node.children, result, depth + 1, max_depth: max_depth)
120
+ end
121
+ end
122
+ end
123
+
124
+ def calculate_relative_path(target_pathname, reference_pathname)
125
+ reference_is_file = !reference_pathname.extname.empty?
126
+ reference_dir = reference_is_file ? reference_pathname.dirname : reference_pathname
127
+
128
+ begin
129
+ relative_path = target_pathname.relative_path_from(reference_dir)
130
+
131
+ relative_str = relative_path.to_s
132
+ if relative_str.start_with?('../')
133
+ relative_path
134
+ else
135
+ Pathname.new("./#{relative_str}")
136
+ end
137
+ rescue
138
+ target_pathname
139
+ end
140
+ end
141
+ end
142
+
143
+ class DocumentTreeNode
144
+ attr_reader :name, :pathname, :title, :children, :depth
145
+
146
+ def initialize(name:, pathname:, title:, depth: 0, is_file: false)
147
+ @name = name
148
+ @pathname = pathname
149
+ @title = title
150
+ @depth = depth
151
+ @is_file = is_file
152
+ @children = []
153
+ end
154
+
155
+ def file?
156
+ @is_file
157
+ end
158
+
159
+ def directory?
160
+ !@is_file
161
+ end
162
+ end
163
+ end
@@ -1,5 +1,4 @@
1
1
  module Mint
2
- # Indicates that a named template is not located anywhere
3
- # in the Mint path.
4
- class TemplateNotFoundException < Exception; end
2
+ class LayoutNotFoundException < Exception; end
3
+ class StyleNotFoundException < Exception; end
5
4
  end
data/lib/mint/helpers.rb CHANGED
@@ -1,193 +1,36 @@
1
1
  require "pathname"
2
- require "tempfile"
3
- require "yaml"
4
- require "active_support/core_ext/string/inflections"
5
2
 
6
3
  module Mint
7
4
  module Helpers
8
- def self.underscore(obj, opts={})
9
- namespaces = obj.to_s.split("::").map do |namespace|
10
- if opts[:ignore_prefix]
11
- namespace[0..1].downcase + namespace[2..-1]
12
- else
13
- namespace
14
- end
15
- end
16
-
17
- string = opts[:namespaces] ? namespaces.join("::") : namespaces.last
18
- string.underscore
19
- end
20
-
21
- # Transforms a String into a URL-ready slug. Properly handles
22
- # ampersands, non-alphanumeric characters, extra hyphens and spaces.
23
- #
24
- # @param [String, #to_s] obj an object to be turned into a slug
25
- # @return [String] a URL-ready slug
26
- def self.slugize(obj)
27
- obj.to_s.downcase.
28
- gsub(/&/, "and").
29
- gsub(/[\s-]+/, "-").
30
- gsub(/[^a-z0-9-]/, "").
31
- gsub(/[-]+/, "-")
32
- end
33
-
34
- # Transforms a potentially hyphenated String into a symbol name.
35
- #
36
- # @param [String, #to_s] obj an object to be turned into a symbol name
37
- # @return [Symbol] a symbol representation of obj
38
- def self.symbolize(obj)
39
- slugize(obj).gsub(/-/, "_").to_sym
40
- end
41
-
42
- # Transforms a String or Pathname into a fully expanded Pathname.
43
- #
44
- # @param [String, Pathname] str_or_path a path to be expanded
45
- # @return [Pathname] an expanded representation of str_or_path
46
- def self.pathize(str_or_path)
47
- case str_or_path
48
- when String
49
- Pathname.new str_or_path
50
- when Pathname
51
- str_or_path
52
- end.expand_path
53
- end
54
-
55
- # Recursively transforms all keys in a Hash into Symbols.
56
- #
57
- # @param [Hash, #[]] map a potentially nested Hash containing symbolizable keys
58
- # @return [Hash] a version of map where all keys are symbols
59
- def self.symbolize_keys(map, opts={})
60
- transform = lambda {|x| opts[:downcase] ? x.downcase : x }
61
-
62
- map.reduce(Hash.new) do |syms,(k,v)|
63
- syms[transform[k].to_sym] =
64
- case v
65
- when Hash
66
- self.symbolize_keys(v, opts)
67
- else
68
- v
69
- end
70
- syms
71
- end
72
- end
73
-
74
- def self.listify(list)
75
- if list.length > 2
76
- list[0..-2].join(", ") + " & " + list.last
5
+ def self.drop_pathname(pathname, levels_to_drop)
6
+ parts = pathname.to_s.split('/').reject(&:empty?)
7
+ if levels_to_drop >= parts.length
8
+ pathname
77
9
  else
78
- list.join(" & ")
79
- end
80
- end
81
-
82
- def self.standardize(metadata, opts={})
83
- table = opts[:table] || {}
84
- metadata.reduce({}) do |hash, (key,value)|
85
- if table[key] && table[key].length == 2
86
- standard_key, standard_type = table[key]
87
- standard_value =
88
- case standard_type
89
- when :array
90
- [*value]
91
- when :string
92
- value
93
- else
94
- # If key/type were not in table
95
- value
96
- end
97
-
98
- hash[standard_key] = standard_value
10
+ dropped_parts = parts.drop(levels_to_drop)
11
+ if dropped_parts.empty?
12
+ Pathname.new('.')
99
13
  else
100
- hash[key] = value
14
+ Pathname.new(dropped_parts.join('/'))
101
15
  end
102
- hash
103
16
  end
104
17
  end
105
-
106
- def self.hashify(list1, list2)
107
- Hash[*list1.zip(list2).flatten]
108
- end
109
-
110
- # Returns the relative path to to_directory from from_directory.
111
- # If to_directory and from_directory have no parents in common besides
112
- # /, returns the absolute directory of to_directory. Assumes no symlinks.
113
- #
114
- # @param [String, Pathname] to_directory the target directory
115
- # @param [String, Pathname] from_directory the starting directory
116
- # @return [Pathname] the relative path to to_directory from
117
- # from_directory, or an absolute path if they have no parents in common
118
- # other than /
119
- def self.normalize_path(to_directory, from_directory)
120
- to_path, from_path = [to_directory, from_directory].map {|d| pathize d }
121
- to_root, from_root = [to_path, from_path].map {|p| p.each_filename.first }
122
- to_root == from_root ?
123
- to_path.relative_path_from(from_path) :
124
- to_path
125
- end
126
-
127
- # Reads Yaml options from file. Updates values with new_opts. Writes
128
- # merged data back to the same file, overwriting previous data.
129
- #
130
- # @param [Hash, #[]] new_opts a set of options to add to the Yaml file
131
- # @param [Pathname, #exist] file a file to read from and write to
132
- # @return [void]
133
- def self.update_yaml!(file, opts={})
134
- curr_opts = if File.exist?(file)
135
- begin
136
- YAML.load_file(file) || {}
137
- rescue Psych::SyntaxError, StandardError
138
- # Handle corrupted YAML gracefully by treating it as empty
139
- {}
140
- end
141
- else
142
- {}
143
- end
144
-
145
- File.open file, "w" do |f|
146
- YAML.dump(curr_opts.merge(opts), f)
18
+
19
+ def self.extract_title_from_file(file_path)
20
+ content = File.read(file_path.to_s)
21
+
22
+ # Check for Title metadata in Markdown front matter
23
+ if content =~ /^---\n.*?^title:\s*(.+)$/m
24
+ return $1.strip.gsub(/^["']|["']$/, '')
147
25
  end
148
- end
149
-
150
- def self.create_temp_file!(basename, extension=nil, &block)
151
- tmp_args = basename && extension ? [basename, extension] : basename
152
- tempfile = Tempfile.new(tmp_args)
153
- block.call(tempfile)
154
- tempfile.flush
155
- tempfile.close
156
- tempfile.path
157
- end
158
-
159
- def self.generate_temp_file!(file)
160
- basename = File.basename file
161
- extension = File.extname file
162
- content = File.read file
163
-
164
- tempfile = Tempfile.new([basename, extension])
165
- tempfile << content
166
- tempfile.flush
167
- tempfile.close
168
- tempfile.path
169
- end
170
-
171
- # Transforms markdown links from .md extensions to .html for digital gardens
172
- #
173
- # @param [String] text the markdown text containing links
174
- # @return [String] the text with transformed links
175
- def self.transform_markdown_links(text)
176
- # Transform relative markdown links like [text](path/file.md) to [text](path/file.html)
177
- text.gsub(/(\[([^\]]*)\]\()([^)]*\.md)(\))/) do |match|
178
- link_start = $1
179
- link_text = $2
180
- link_url = $3
181
- link_end = $4
182
-
183
- # Only transform relative links (not absolute URLs)
184
- if link_url !~ /^https?:\/\//
185
- new_url = link_url.gsub(/\.md$/, '.html')
186
- "#{link_start}#{new_url}#{link_end}"
187
- else
188
- match
189
- end
26
+
27
+ # Check for first markdown heading
28
+ if content =~ /^#\s+(.+)$/
29
+ return $1.strip
190
30
  end
31
+
32
+ # Fall back to upcased filename with underscores/hyphens converted to spaces
33
+ file_path.basename('.*').to_s.tr('_-', ' ').upcase
191
34
  end
192
35
  end
193
- end
36
+ end
data/lib/mint/layout.rb CHANGED
@@ -1,14 +1,31 @@
1
- require "mint/resource"
1
+ require "pathname"
2
2
 
3
3
  module Mint
4
- class Layout < Resource
5
- # Creates a new Layout object using a mandatory source file
6
- # and optional configuration options.
4
+ module Layout
5
+ HTML_EXTENSIONS = ["html", "erb"]
6
+
7
+ # Indicates whether the file is a valid layout file
7
8
  #
8
- # @param [String] source the absolute or relative file path
9
- def initialize(source, root: nil, destination: nil, context: nil, name: nil, &block)
10
- super(source, root: root, destination: destination, context: context, name: name, &block)
11
- self.type = :layout
9
+ # @param [Pathname] pathname the pathname to check
10
+ # @return [Boolean] true if the file is a valid layout file
11
+ def self.valid?(pathname)
12
+ HTML_EXTENSIONS.map {|ext| "layout.#{ext}" }.include? pathname.basename.to_s
13
+ end
14
+
15
+ # Returns the layout file for the given template name
16
+ #
17
+ # @param [String] name the template name or directory path to look up
18
+ # @return [Pathname] path to the layout file
19
+ def self.find_by_name(name)
20
+ find_in_directory Template.find_directory_by_name(name)
21
+ end
22
+
23
+ # Finds the layout file in a specific directory
24
+ #
25
+ # @param [Pathname] directory the directory to look in
26
+ # @return [Pathname] path to the layout file
27
+ def self.find_in_directory(directory)
28
+ directory&.children&.select(&:file?)&.select(&method(:valid?))&.first
12
29
  end
13
30
  end
14
- end
31
+ end
@@ -0,0 +1,32 @@
1
+ module Mint
2
+ module Renderers
3
+ class Css
4
+ def self.render_file(css_file)
5
+ self.process(css_file.read, css_file.dirname)
6
+ end
7
+
8
+ def self.process(css_content, base_dir)
9
+ css_content.gsub(/@import\s+["']([^"']+)["'];?/) do |match|
10
+ import_path = Pathname.new $1
11
+
12
+ if import_path.relative?
13
+ full_path = import_path.expand_path base_dir
14
+ else
15
+ full_path = base_dir + import_path
16
+ end
17
+
18
+ if full_path.extname != '.css'
19
+ full_path.rename(full_path.to_s + '.css')
20
+ end
21
+
22
+ if full_path.exist?
23
+ imported_content = full_path.read
24
+ self.process(imported_content, full_path.dirname)
25
+ else
26
+ match
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ require "erb"
2
+
3
+ module Mint
4
+ module Renderers
5
+ class Erb
6
+ def self.render(content, variables)
7
+ ERB.new(content).result_with_hash(variables)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ require 'redcarpet'
2
+
3
+ module Mint
4
+ module Renderers
5
+ class Markdown
6
+ def self.render(text, variables = {}, **markdown_options)
7
+ # Use default rendering options (all extra options turned off)
8
+ # See documentation for more information:
9
+ # https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
10
+ renderer_options = {
11
+ # filter_html: false,
12
+ # no_images: false,
13
+ # no_links: false,
14
+ # no_styles: false,
15
+ # escape_html: false,
16
+ # safe_links_only: false,
17
+ # with_toc_data: false,
18
+ # hard_wrap: false,
19
+ # prettify: false
20
+ }
21
+
22
+ markdown_options = {
23
+ tables: true,
24
+ autolink: true,
25
+ no_intra_emphasis: true,
26
+ fenced_code_blocks: true,
27
+ strikethrough: true,
28
+ superscript: true,
29
+ footnotes: true,
30
+ highlight: true,
31
+ quote: true,
32
+ space_after_headers: true,
33
+ underline: true,
34
+ # Additional options
35
+ # lax_html_blocks: false,
36
+ # disable_indented_code_blocks: false
37
+ }.merge(markdown_options)
38
+
39
+ renderer = Redcarpet::Render::HTML.new(renderer_options)
40
+ parser = Redcarpet::Markdown.new(renderer, markdown_options)
41
+ parser.render text
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/mint/style.rb CHANGED
@@ -1,41 +1,31 @@
1
- require "mint/resource"
1
+ require "pathname"
2
2
 
3
3
  module Mint
4
- class Style < Resource
5
- # Creates a new Style object using a mandatory source file
6
- # and optional configuration options.
4
+ module Style
5
+ CSS_EXTENSIONS = ["css"]
6
+
7
+ # Indicates whether the file is a valid stylesheet
7
8
  #
8
- # @param [String] source the absolute or relative file path
9
- def initialize(source, root: nil, destination: nil, context: nil, name: nil, &block)
10
- super(source, root: root, destination: destination, context: context, name: name, &block)
11
- self.type = :style
12
-
13
- # We want to render final stylesheet to the /css subdirectory if
14
- # an output directory is not specified and we are dealing with
15
- # a named template (not a local file). If we don't do this, the rendered
16
- # CSS file might be picked up next time we look for a named template
17
- # in this directory, and the (correct) SASS file won't be picked up.
18
- # However, if a destination directory is already specified, we
19
- # leave it alone.
20
- if Mint.template?(self.source_directory) and rendered?
21
- tmp_dir = Mint.path_for_scope(:user) + "tmp"
22
- self.destination ||= tmp_dir.to_s
23
- self.root = "/"
24
- end
9
+ # @param [Pathname] pathname the pathname to check
10
+ # @return [Boolean] true if the file is a valid stylesheet
11
+ def self.valid?(pathname)
12
+ CSS_EXTENSIONS.map {|ext| "style.#{ext}" }.include? pathname.basename.to_s
25
13
  end
26
-
27
- # Determines whether a Style object is supposed to be rendered.
14
+
15
+ # Returns the style file for the given template name
28
16
  #
29
- # @return [Boolean] whether or not style should be rendered
30
- def rendered?
31
- true # All styles need rendering now (CSS for imports, Sass for compilation)
17
+ # @param [String] name the template name to look up
18
+ # @return [Pathname] path to the style file
19
+ def self.find_by_name(name)
20
+ find_in_directory Template.find_directory_by_name(name)
32
21
  end
33
22
 
34
- # Renders a Style object through Tilt template system
23
+ # Finds the style file in a specific directory
35
24
  #
36
- # @return [String] a rendered stylesheet
37
- def render
38
- super
25
+ # @param [Pathname] directory the directory to look in
26
+ # @return [Pathname] path to the style file
27
+ def self.find_in_directory(directory)
28
+ directory&.children&.select(&:file?)&.select(&method(:valid?))&.first
39
29
  end
40
30
  end
41
- end
31
+ end
@@ -0,0 +1,30 @@
1
+ require "pathname"
2
+
3
+ module Mint
4
+ module Template
5
+ # Indicates whether the directory is a valid template directory.
6
+ #
7
+ # @param [Pathname] directory the directory to check
8
+ # @return [Boolean] true if the directory is a valid template directory
9
+ def self.valid?(directory)
10
+ # Note that typically templates have only a stylesheet, although they can
11
+ # optionally include a layout file. Most templates can get by with the layout
12
+ # provided by the default template, which is automatically used if no layout
13
+ # file is provided in the template directory.
14
+ directory.children.
15
+ select(&:file?).
16
+ select(&Style.method(:valid?))
17
+ end
18
+
19
+ # Finds a template directory by name
20
+ #
21
+ # @param [String] name the template name to find
22
+ # @return [Pathname] path to the template directory
23
+ def self.find_directory_by_name(name)
24
+ Mint::PATH.
25
+ map {|p| p + Mint::TEMPLATES_DIRECTORY + name }.
26
+ select(&:exist?).
27
+ first
28
+ end
29
+ end
30
+ end
data/lib/mint/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mint
2
- VERSION = "0.8.1"
2
+ VERSION = "0.10.0"
3
3
  end