ruhoh 0.0.2 → 0.0.3

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 (87) hide show
  1. data/Gemfile +13 -0
  2. data/README.md +5 -53
  3. data/Rakefile +56 -0
  4. data/bin/ruhoh +23 -14
  5. data/lib/ruhoh/client/client.rb +310 -0
  6. data/lib/ruhoh/client/help.yml +56 -0
  7. data/lib/ruhoh/compiler.rb +16 -19
  8. data/lib/ruhoh/converters/converter.rb +30 -3
  9. data/lib/ruhoh/db.rb +7 -17
  10. data/lib/ruhoh/deployers/s3.rb +71 -0
  11. data/lib/ruhoh/friend.rb +71 -0
  12. data/lib/ruhoh/page.rb +41 -11
  13. data/lib/ruhoh/parsers/drafts.rb +54 -0
  14. data/lib/ruhoh/parsers/layouts.rb +14 -9
  15. data/lib/ruhoh/parsers/pages.rb +47 -35
  16. data/lib/ruhoh/parsers/partials.rb +14 -2
  17. data/lib/ruhoh/parsers/posts.rb +139 -88
  18. data/lib/ruhoh/parsers/routes.rb +4 -8
  19. data/lib/ruhoh/parsers/site.rb +2 -8
  20. data/lib/ruhoh/previewer.rb +48 -0
  21. data/lib/ruhoh/templaters/base.rb +53 -0
  22. data/lib/ruhoh/templaters/helpers.rb +159 -0
  23. data/lib/ruhoh/templaters/rmustache.rb +29 -0
  24. data/lib/ruhoh/utils.rb +25 -7
  25. data/lib/ruhoh/version.rb +1 -1
  26. data/lib/ruhoh/watch.rb +22 -9
  27. data/lib/ruhoh.rb +74 -29
  28. data/ruhoh.gemspec +70 -9
  29. data/scaffolds/blog/_config.yml +33 -0
  30. data/scaffolds/blog/_drafts/.gitkeep +0 -0
  31. data/scaffolds/blog/_posts/.gitkeep +0 -0
  32. data/scaffolds/blog/_site.yml +16 -0
  33. data/scaffolds/blog/_templates/partials/categories_list +3 -0
  34. data/scaffolds/blog/_templates/partials/pages_list +7 -0
  35. data/scaffolds/blog/_templates/partials/posts_collate +9 -0
  36. data/scaffolds/blog/_templates/partials/posts_list +1 -0
  37. data/scaffolds/blog/_templates/partials/tags_list +3 -0
  38. data/scaffolds/blog/_templates/syntax/google_prettify/default.css +52 -0
  39. data/scaffolds/blog/_templates/syntax/google_prettify/desert.css +34 -0
  40. data/scaffolds/blog/_templates/syntax/google_prettify/sons-of-obsidian.css +117 -0
  41. data/scaffolds/blog/_templates/syntax/google_prettify/sunburst.css +51 -0
  42. data/scaffolds/blog/_templates/syntax/google_prettify/twitter-bootstrap.css +30 -0
  43. data/scaffolds/blog/_templates/themes/twitter/bootstrap/css/bootstrap.min.css +689 -0
  44. data/scaffolds/blog/_templates/themes/twitter/bootstrap/img/glyphicons-halflings-white.png +0 -0
  45. data/scaffolds/blog/_templates/themes/twitter/bootstrap/img/glyphicons-halflings.png +0 -0
  46. data/scaffolds/blog/_templates/themes/twitter/css/style.css +68 -0
  47. data/scaffolds/blog/_templates/themes/twitter/layouts/default.html +64 -0
  48. data/scaffolds/blog/_templates/themes/twitter/layouts/page.html +13 -0
  49. data/scaffolds/blog/_templates/themes/twitter/layouts/post.html +55 -0
  50. data/scaffolds/blog/_templates/themes/twitter/manifest.yml +11 -0
  51. data/scaffolds/blog/about.md +5 -0
  52. data/scaffolds/blog/archive.html +11 -0
  53. data/scaffolds/blog/categories.html +21 -0
  54. data/scaffolds/blog/config.ru +9 -0
  55. data/scaffolds/blog/index.html +13 -0
  56. data/scaffolds/blog/pages.html +14 -0
  57. data/scaffolds/blog/tags.html +21 -0
  58. data/scaffolds/layout.html +3 -0
  59. data/scaffolds/page.html +6 -0
  60. data/scaffolds/post.html +8 -0
  61. data/scaffolds/theme/css/style.css +0 -0
  62. data/scaffolds/theme/images/.gitkeep +0 -0
  63. data/scaffolds/theme/layouts/default.html +17 -0
  64. data/scaffolds/theme/layouts/page.html +7 -0
  65. data/scaffolds/theme/layouts/post.html +8 -0
  66. data/scaffolds/theme/partials/.gitkeep +0 -0
  67. data/spec/db_spec.rb +88 -0
  68. data/spec/page_spec.rb +200 -0
  69. data/spec/parsers/layouts_spec.rb +32 -0
  70. data/spec/parsers/pages_spec.rb +97 -0
  71. data/spec/parsers/posts_spec.rb +301 -0
  72. data/spec/parsers/routes_spec.rb +45 -0
  73. data/spec/parsers/site_spec.rb +32 -0
  74. data/spec/setup_spec.rb +72 -0
  75. data/spec/spec_helper.rb +23 -0
  76. data/system_partials/analytics/getclicky +12 -0
  77. data/system_partials/analytics/google +11 -0
  78. data/system_partials/comments/disqus +13 -0
  79. data/system_partials/comments/facebook +9 -0
  80. data/system_partials/comments/intensedebate +6 -0
  81. data/system_partials/comments/livefyre +6 -0
  82. data/system_partials/syntax/google_prettify +11 -0
  83. metadata +84 -23
  84. data/lib/ruhoh/client.rb +0 -28
  85. data/lib/ruhoh/preview.rb +0 -36
  86. data/lib/ruhoh/templaters/helper_mustache.rb +0 -109
  87. data/lib/ruhoh/templaters/templater.rb +0 -39
data/lib/ruhoh/db.rb CHANGED
@@ -3,24 +3,12 @@ require "observer"
3
3
  class Ruhoh
4
4
 
5
5
  # Public: Database class for interacting with "data" in Ruhoh.
6
- #
7
6
  class DB
8
-
9
7
  class << self
10
8
  include Observable
11
- attr_reader :site, :routes, :posts, :pages, :layouts, :partials
9
+ WhiteList = [:site, :posts, :drafts, :pages, :routes, :layouts, :partials]
10
+ self.__send__ :attr_reader, *WhiteList
12
11
 
13
- # Note this is class-level so you have to call it manually.
14
- def initialize
15
- @site = ''
16
- @routes = ''
17
- @posts = ''
18
- @pages = ''
19
- @layouts = ''
20
- @partials = ''
21
- self.update!
22
- end
23
-
24
12
  def update(name)
25
13
  self.instance_variable_set("@#{name}",
26
14
  case name
@@ -30,6 +18,8 @@ class Ruhoh
30
18
  Ruhoh::Parsers::Routes.generate
31
19
  when :posts
32
20
  Ruhoh::Parsers::Posts.generate
21
+ when :drafts
22
+ Ruhoh::Parsers::Drafts.generate
33
23
  when :pages
34
24
  Ruhoh::Parsers::Pages.generate
35
25
  when :layouts
@@ -45,9 +35,9 @@ class Ruhoh
45
35
  end
46
36
 
47
37
  def update!
48
- self.instance_variables.each { |var|
49
- self.__send__ :update, var.to_s.gsub('@', '').to_sym
50
- }
38
+ WhiteList.each do |var|
39
+ self.__send__ :update, var
40
+ end
51
41
  end
52
42
 
53
43
  end #self
@@ -0,0 +1,71 @@
1
+ require 'aws/s3'
2
+
3
+ class Ruhoh
4
+
5
+ module Deployers
6
+
7
+ # Deploy to Amazon S3
8
+ # See http://amazon.rubyforge.org/ for usage.
9
+ class AmazonS3 < AWS::S3::S3Object
10
+
11
+ def initialize
12
+ credentials = Ruhoh::Utils.parse_file_as_yaml(Ruhoh.paths.site_source, "_deploy.yml")['s3']
13
+ self.connect(credentials)
14
+ self.ensure_bucket(credentials["bucket"])
15
+ #set_current_bucket_to(credentials["bucket"])
16
+ @bucket = credentials["bucket"]
17
+ end
18
+
19
+ def connect(credentials)
20
+ AWS::S3::Base.establish_connection!({
21
+ :access_key_id => credentials["access_key_id"],
22
+ :secret_access_key => credentials["secret_access_key"]
23
+ })
24
+ end
25
+
26
+ def deploy(compiled_directory)
27
+ FileUtils.cd(compiled_directory) {
28
+ Dir.glob("**/**") do |filepath|
29
+ next if FileTest.directory?(file)
30
+ self.store(filepath)
31
+ end
32
+ }
33
+ end
34
+
35
+ def ensure_bucket(bucket)
36
+ AWS::S3::Bucket.find(bucket)
37
+ rescue
38
+ Ruhoh::Friend.say {
39
+ yellow "'#{@bucket}' bucket not found, trying to create..."
40
+ }
41
+ AWS::S3::Bucket.create(bucket, :access => :public_read)
42
+
43
+ if AWS::S3::Service.response.success?
44
+ Ruhoh::Friend.say { green "Bucket created!" }
45
+ else
46
+ Ruhoh::Friend.say {
47
+ red "Bucket creation failed!"
48
+ plain "Perhaps you will need to manually create the bucket."
49
+ }
50
+ exit
51
+ end
52
+ end
53
+
54
+ # save/update a file to s3
55
+ def store(filepath)
56
+ File.open(filepath) do |file|
57
+ AWS::S3::S3Object.store(filepath, file, @bucket, :access => :public_read)
58
+ end
59
+
60
+ if AWS::S3::Service.response.success?
61
+ Ruhoh::Friend.say { green "#{filepath}: success!" }
62
+ else
63
+ Ruhoh::Friend.say { green "#{filepath}: failure!" }
64
+ end
65
+ end
66
+
67
+ end #S3
68
+
69
+ end #Deployers
70
+
71
+ end #Ruhoh
@@ -0,0 +1,71 @@
1
+ class Ruhoh
2
+
3
+ # The Friend is good for conversation.
4
+ # He tells you what's going on.
5
+ # Implementation is largely copied from rspec gem: http://rspec.info/
6
+ class Friend
7
+
8
+ class << self
9
+
10
+ def say(&block)
11
+ self.instance_eval(&block)
12
+ end
13
+
14
+ # TODO: Adds ability to disable if color is not supported?
15
+ def color_enabled?
16
+ true
17
+ end
18
+
19
+ def list(caption, listings)
20
+ red(" " + caption)
21
+ listings.each do |pair|
22
+ cyan(" - " + pair[0])
23
+ cyan(" " + pair[1])
24
+ end
25
+ end
26
+
27
+ def color(text, color_code)
28
+ puts color_enabled? ? "#{color_code}#{text}\e[0m" : text
29
+ end
30
+
31
+ def plain(text)
32
+ puts text
33
+ end
34
+
35
+ def bold(text)
36
+ color(text, "\e[1m")
37
+ end
38
+
39
+ def red(text)
40
+ color(text, "\e[31m")
41
+ end
42
+
43
+ def green(text)
44
+ color(text, "\e[32m")
45
+ end
46
+
47
+ def yellow(text)
48
+ color(text, "\e[33m")
49
+ end
50
+
51
+ def blue(text)
52
+ color(text, "\e[34m")
53
+ end
54
+
55
+ def magenta(text)
56
+ color(text, "\e[35m")
57
+ end
58
+
59
+ def cyan(text)
60
+ color(text, "\e[36m")
61
+ end
62
+
63
+ def white(text)
64
+ color(text, "\e[37m")
65
+ end
66
+
67
+ end #self
68
+
69
+ end #Friend
70
+
71
+ end #Ruhoh
data/lib/ruhoh/page.rb CHANGED
@@ -1,35 +1,59 @@
1
1
  class Ruhoh
2
2
 
3
3
  class Page
4
- attr_reader :data, :content, :sub_layout, :master_layout
4
+ attr_reader :id, :data, :content, :sub_layout, :master_layout
5
+ attr_accessor :templater, :converter
5
6
 
7
+ def initialize
8
+ @templater = Ruhoh::Templaters::Base
9
+ @converter = Ruhoh::Converter
10
+ end
11
+
6
12
  # Public: Change this page using an id.
7
13
  def change(id)
8
14
  @data = nil
9
- @data = id =~ Regexp.new("^#{Ruhoh.folders.posts}") ? Ruhoh::DB.posts['dictionary'][id] : Ruhoh::DB.pages[id]
15
+
16
+ @data = if id =~ Regexp.new("^#{Ruhoh.folders.posts}")
17
+ Ruhoh::DB.posts['dictionary'][id]
18
+ elsif id =~ Regexp.new("^#{Ruhoh.folders.drafts}")
19
+ Ruhoh::DB.drafts[id]
20
+ else
21
+ Ruhoh::DB.pages[id]
22
+ end
23
+
10
24
  raise "Page #{id} not found in database" unless @data
11
25
  @id = id
12
26
  end
13
27
 
14
28
  # Public: Change this page using a URL.
15
29
  def change_with_url(url)
16
- url = '/index.html' if url == '/'
17
- id = Ruhoh::DB.routes[url]
30
+ id = if url =~ Regexp.new("^/#{Ruhoh.folders.drafts}")
31
+ url.gsub(/^\//,'')
32
+ else
33
+ Ruhoh::DB.routes[url]
34
+ end
35
+
18
36
  raise "Page id not found for url: #{url}" unless id
19
37
  self.change(id)
20
38
  end
21
39
 
22
40
  def render
41
+ raise "ID is null: Id must be set via page.change(id) or page.change_with_url(url)" if @id.nil?
23
42
  self.process_layouts
24
43
  self.process_content
25
- Ruhoh::Templater.expand_and_render(self)
44
+ @templater.render(self)
26
45
  end
27
46
 
28
47
  def process_layouts
29
- @sub_layout = Ruhoh::DB.layouts[@data['layout']]
30
-
31
- if @sub_layout['data']['layout']
48
+ raise "ID is null: Id must be set via page.change(id) or page.change_with_url(url)" if @id.nil?
49
+ if @data['layout']
50
+ @sub_layout = Ruhoh::DB.layouts[@data['layout']]
51
+ raise "Layout does not exist: #{@data['layout']}" unless @sub_layout
52
+ end
53
+
54
+ if @sub_layout && @sub_layout['data']['layout']
32
55
  @master_layout = Ruhoh::DB.layouts[@sub_layout['data']['layout']]
56
+ raise "Layout does not exist: #{@sub_layout['data']['layout']}" unless @master_layout
33
57
  end
34
58
  end
35
59
 
@@ -37,14 +61,18 @@ class Ruhoh
37
61
  # in order to invoke converters on the result.
38
62
  # Converters (markdown) always choke on the templating language.
39
63
  def process_content
40
- @content = Ruhoh::Utils.parse_file(Ruhoh.paths.site_source, @id)['content']
41
- @content = Ruhoh::Templater.render(@content, self)
42
- @content = Ruhoh::Converter.convert(self)
64
+ raise "ID is null: Id must be set via page.change(id) or page.change_with_url(url)" if @id.nil?
65
+ data = Ruhoh::Utils.parse_file(Ruhoh.paths.site_source, @id)
66
+ raise "Invalid Frontmatter in page: #{@id}" if data.empty?
67
+
68
+ @content = @templater.parse(data['content'], self)
69
+ @content = @converter.convert(self)
43
70
  end
44
71
 
45
72
  # Public: Return page attributes suitable for inclusion in the
46
73
  # 'payload' of the given templater.
47
74
  def attributes
75
+ raise "ID is null: Id must be set via page.change(id) or page.change_with_url(url)" if @id.nil?
48
76
  @data['content'] = @content
49
77
  @data
50
78
  end
@@ -53,7 +81,9 @@ class Ruhoh
53
81
  #
54
82
  # Returns: [String] The relative path to the compiled file for this page.
55
83
  def compiled_path
84
+ raise "ID is null: Id must be set via page.change(id) or page.change_with_url(url)" if @id.nil?
56
85
  path = CGI.unescape(@data['url']).gsub(/^\//, '') #strip leading slash.
86
+ path = "index.html" if path.empty?
57
87
  path += '/index.html' unless path =~ /\.html$/
58
88
  path
59
89
  end
@@ -0,0 +1,54 @@
1
+ class Ruhoh
2
+ module Parsers
3
+ module Drafts
4
+
5
+ def self.generate
6
+ raise "Ruhoh.config cannot be nil.\n To set config call: Ruhoh.setup" unless Ruhoh.config
7
+
8
+ dictionary = {}
9
+ invalid = []
10
+
11
+ self.files.each do |filename|
12
+ parsed_page = Ruhoh::Utils.parse_file(filename)
13
+ if parsed_page.empty?
14
+ error = "Invalid YAML Front Matter. Ensure this page has valid YAML, even if it's empty."
15
+ invalid << [filename, error] ; next
16
+ end
17
+
18
+ data = parsed_page['data']
19
+ data['id'] = filename
20
+ data['url'] = "/#{filename}"
21
+ dictionary[filename] = data
22
+ end
23
+
24
+ self.report(dictionary, invalid)
25
+ dictionary
26
+ end
27
+
28
+ def self.files
29
+ FileUtils.cd(Ruhoh.paths.site_source) {
30
+ return Dir["#{Ruhoh.folders.drafts}/**/*.*"].select { |filename|
31
+ next if FileTest.directory?(filename)
32
+ next if ['.'].include? filename[0]
33
+ true
34
+ }
35
+ }
36
+ end
37
+
38
+ def self.report(dictionary, invalid)
39
+ output = "#{dictionary.count}/#{dictionary.count + invalid.count} drafts processed."
40
+ if dictionary.empty? && invalid.empty?
41
+ Ruhoh::Friend.say { plain "0 drafts to process." }
42
+ elsif invalid.empty?
43
+ Ruhoh::Friend.say { green output }
44
+ else
45
+ Ruhoh::Friend.say {
46
+ yellow output
47
+ list "Drafts not processed:", invalid
48
+ }
49
+ end
50
+ end
51
+
52
+ end #Drafts
53
+ end #Parsers
54
+ end #Ruhoh
@@ -1,25 +1,30 @@
1
1
  class Ruhoh
2
-
3
2
  module Parsers
4
-
5
3
  module Layouts
6
4
 
7
5
  # Generate layouts only from the active theme.
8
6
  def self.generate
9
7
  layouts = {}
8
+
9
+ self.files.each do |filename|
10
+ id = File.basename(filename, File.extname(filename))
11
+ layouts[id] = Ruhoh::Utils.parse_file(Ruhoh.paths.layouts, filename)
12
+ raise "Invalid Frontmatter in layout: #{filename}" if layouts[id].empty?
13
+ end
14
+
15
+ layouts
16
+ end
17
+
18
+ def self.files
10
19
  FileUtils.cd(Ruhoh.paths.layouts) {
11
- Dir.glob("**/*.*") { |filename|
20
+ return Dir["**/*.*"].select { |filename|
12
21
  next if FileTest.directory?(filename)
13
22
  next if ['_','.'].include? filename[0]
14
- id = File.basename(filename, File.extname(filename))
15
- layouts[id] = Ruhoh::Utils.parse_file(Ruhoh.paths.layouts, filename)
23
+ true
16
24
  }
17
25
  }
18
- layouts
19
26
  end
20
-
27
+
21
28
  end #Layouts
22
-
23
29
  end #Parsers
24
-
25
30
  end #Ruhoh
@@ -8,59 +8,71 @@ class Ruhoh
8
8
  #
9
9
  def self.generate
10
10
  raise "Ruhoh.config cannot be nil.\n To set config call: Ruhoh.setup" unless Ruhoh.config
11
- puts "=> Generating Pages..."
12
11
 
13
- invalid_pages = []
12
+ pages = self.files
13
+ invalid = []
14
14
  dictionary = {}
15
- total_pages = 0
16
- FileUtils.cd(Ruhoh.paths.site_source) {
17
- Dir.glob("**/*.*") { |filename|
18
- next unless self.is_valid_page?(filename)
19
- total_pages += 1
20
15
 
21
- File.open(filename) do |page|
22
- front_matter = page.read.match(Ruhoh::Utils::FMregex)
23
- if !front_matter
24
- invalid_pages << filename ; next
25
- end
16
+ pages.each do |filename|
17
+ parsed_page = Ruhoh::Utils.parse_file(filename)
18
+ if parsed_page.empty?
19
+ error = "Invalid Yaml Front Matter.\n Ensure this page has valid YAML, even if it's empty."
20
+ invalid << [filename, error] ; next
21
+ end
22
+
23
+ parsed_page['data']['id'] = filename
24
+ parsed_page['data']['url'] = self.permalink(parsed_page['data'])
25
+ parsed_page['data']['title'] = parsed_page['data']['title'] || self.titleize(filename)
26
26
 
27
- data = YAML.load(front_matter[0].gsub(/---\n/, "")) || {}
28
- data['id'] = filename
29
- data['url'] = self.permalink(data)
30
- data['title'] = data['title'] || self.titleize(filename)
31
-
32
- dictionary[filename] = data
33
- end
27
+ dictionary[filename] = parsed_page['data']
28
+ end
29
+
30
+ report = "#{pages.count - invalid.count }/#{pages.count} pages processed."
31
+
32
+ if pages.count.zero? && invalid.empty?
33
+ Ruhoh::Friend.say { plain "0 pages to process." }
34
+ elsif invalid.empty?
35
+ Ruhoh::Friend.say { green report }
36
+ else
37
+ Ruhoh::Friend.say {
38
+ yellow report
39
+ list "Pages not processed:", invalid
34
40
  }
35
- }
41
+ end
36
42
 
37
- if invalid_pages.empty?
38
- puts "=> #{total_pages - invalid_pages.count }/#{total_pages} pages processed."
39
- else
40
- puts "=> Invalid pages not processed:"
41
- puts invalid_pages.to_yaml
42
- end
43
-
44
43
  dictionary
45
44
  end
46
-
47
- def self.is_valid_page?(filename)
48
- return false if FileTest.directory?(filename)
49
- return false if ['_', '.'].include? filename[0]
50
- return false if Ruhoh.filters.pages['names'].include? filename
51
- Ruhoh.filters.pages['regexes'].each {|regex| return false if filename =~ regex }
45
+
46
+ def self.files
47
+ FileUtils.cd(Ruhoh.paths.site_source) {
48
+ return Dir["**/*.*"].select { |filename|
49
+ next unless self.is_valid_page?(filename)
50
+ true
51
+ }
52
+ }
53
+ end
54
+
55
+ def self.is_valid_page?(filepath)
56
+ return false if FileTest.directory?(filepath)
57
+ return false if ['_', '.'].include? filepath[0]
58
+ return false if Ruhoh.filters.pages['names'].include? filepath
59
+ Ruhoh.filters.pages['regexes'].each {|regex| return false if filepath =~ regex }
52
60
  true
53
61
  end
54
62
 
55
63
  def self.titleize(filename)
56
- File.basename( filename, File.extname(filename) ).gsub(/[\W\_]/, ' ').gsub(/\b\w/){$&.upcase}
64
+ name = File.basename( filename, File.extname(filename) )
65
+ name = filename.split('/')[-2] if name == 'index' && !filename.index('/').nil?
66
+ name.gsub(/[\W\_]/, ' ').gsub(/\b\w/){$&.upcase}
57
67
  end
58
68
 
59
69
  def self.permalink(page)
60
70
  url = '/' + page['id'].gsub(File.extname(page['id']), '.html')
61
-
62
71
  # sanitize url
63
72
  url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
73
+ url.gsub!(/\/index.html$/, '')
74
+ url = "/" if url.empty?
75
+
64
76
  url
65
77
  end
66
78
 
@@ -5,7 +5,19 @@ class Ruhoh
5
5
  module Partials
6
6
 
7
7
  def self.generate
8
- self.process(Ruhoh.paths.global_partials).merge( self.process(Ruhoh.paths.partials) )
8
+ self.system_partials.merge(self.global_partials).merge(self.theme_partials)
9
+ end
10
+
11
+ def self.theme_partials
12
+ self.process(Ruhoh.paths.partials)
13
+ end
14
+
15
+ def self.global_partials
16
+ self.process(Ruhoh.paths.global_partials)
17
+ end
18
+
19
+ def self.system_partials
20
+ self.process(File.join(Ruhoh::Root, 'system_partials'))
9
21
  end
10
22
 
11
23
  def self.process(path)
@@ -16,7 +28,7 @@ class Ruhoh
16
28
  Dir.glob("**/*").each { |filename|
17
29
  next if FileTest.directory?(filename)
18
30
  next if ['.'].include? filename[0]
19
- partials[filename] = File.open(filename).read
31
+ File.open(filename) { |f| partials[filename] = f.read }
20
32
  }
21
33
  }
22
34
  partials