henshin 0.2.2 → 0.3.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 (48) hide show
  1. data/.gitignore +1 -1
  2. data/README.markdown +0 -1
  3. data/Rakefile +4 -1
  4. data/VERSION +1 -1
  5. data/bin/files.rb +46 -0
  6. data/bin/henshin +47 -79
  7. data/henshin.gemspec +37 -14
  8. data/lib/henshin.rb +50 -36
  9. data/lib/henshin/archive.rb +161 -0
  10. data/lib/henshin/categories.rb +6 -1
  11. data/lib/henshin/ext.rb +2 -53
  12. data/lib/henshin/gen.rb +16 -15
  13. data/lib/henshin/plugin.rb +20 -7
  14. data/lib/henshin/plugins/highlight.rb +31 -0
  15. data/lib/henshin/plugins/liquid.rb +48 -14
  16. data/lib/henshin/plugins/maruku.rb +3 -4
  17. data/lib/henshin/plugins/sass.rb +7 -6
  18. data/lib/henshin/plugins/textile.rb +3 -4
  19. data/lib/henshin/post.rb +50 -8
  20. data/lib/henshin/site.rb +60 -34
  21. data/lib/henshin/tags.rb +5 -1
  22. data/test/site/css/{print.sass → includes/reset.sass} +0 -3
  23. data/test/site/css/{screen.css → print.css} +1 -4
  24. data/test/site/css/screen.sass +70 -0
  25. data/test/site/includes/head.html +1 -0
  26. data/test/site/index.html +12 -2
  27. data/test/site/layouts/archive_date.html +19 -0
  28. data/test/site/layouts/archive_month.html +19 -0
  29. data/test/site/layouts/archive_year.html +19 -0
  30. data/test/site/layouts/category_index.html +5 -4
  31. data/test/site/layouts/category_page.html +2 -2
  32. data/test/site/layouts/main.html +1 -36
  33. data/test/site/layouts/post.html +15 -5
  34. data/test/site/layouts/tag_index.html +3 -3
  35. data/test/site/layouts/tag_page.html +2 -2
  36. data/test/site/options.yaml +7 -4
  37. data/test/site/posts/Testing-Stuff.markdown +7 -1
  38. data/test/test_archives.rb +27 -0
  39. data/test/test_categories.rb +0 -0
  40. data/test/test_gens.rb +28 -7
  41. data/test/test_options.rb +4 -2
  42. data/test/test_posts.rb +50 -14
  43. data/test/test_site.rb +55 -7
  44. data/test/test_statics.rb +0 -0
  45. data/test/test_tags.rb +0 -0
  46. data/test/text_exts.rb +0 -0
  47. metadata +86 -17
  48. data/lib/henshin/plugins/pygments.rb +0 -17
@@ -0,0 +1,161 @@
1
+ module Henshin
2
+
3
+ class Archive
4
+
5
+ attr_accessor :config
6
+
7
+ def initialize( site )
8
+ @archive = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = []} }}
9
+ @site = site
10
+ @config = site.config
11
+ end
12
+
13
+ def add_post( post )
14
+ date = post.date
15
+ @archive[date.year.to_s][date.month.to_s][date.day.to_s] << post.to_hash
16
+ end
17
+
18
+ # Turns the whole archive into a hash. Probably the least efficient thing in the world, but it works
19
+ def to_hash
20
+ if @hashed
21
+ @hashed
22
+ else
23
+ @hashed = Hash.new do |h, k|
24
+ h[k] = Hash.new do |h, k| # years
25
+ if k == 'posts'
26
+ h[k] = []
27
+ else
28
+ h[k] = Hash.new do |h, k| # months
29
+ if k == 'posts'
30
+ h[k] = []
31
+ else
32
+ h[k] = Hash.new do |h, k| # days
33
+ if k == 'posts'
34
+ h[k] = []
35
+ else
36
+ h[k] = {}
37
+ end
38
+ end # /days
39
+ end
40
+ end # /months
41
+ end
42
+ end # /years
43
+ end
44
+ @archive.each do |y, month|
45
+ month.each do |m, date|
46
+ date.each do |d, p|
47
+ @hashed[y]['posts'] << p
48
+ @hashed[y][m]['posts'] << p
49
+ @hashed[y][m][d]['posts'] << p
50
+
51
+ @hashed[y]['posts'].flatten!
52
+ @hashed[y][m]['posts'].flatten!
53
+ @hashed[y][m][d]['posts'].flatten!
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+ # Creates a hash with posts separated by year, month then date
62
+ def to_date_hash
63
+ r = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = []} }}
64
+ @archive.each do |year, m|
65
+ m.each do |month, d|
66
+ d.each do |date, p|
67
+ r[year][month][date] << p
68
+ r[year][month][date].flatten!
69
+ end
70
+ end
71
+ end
72
+ r
73
+ end
74
+
75
+ # Creates a hash with posts separated by year then month
76
+ def to_month_hash
77
+ r = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = []} }
78
+ @archive.each do |year, m|
79
+ m.each do |month, d|
80
+ d.each do |date, p|
81
+ r[year][month] << p
82
+ r[year][month].flatten!
83
+ end
84
+ end
85
+ end
86
+ r
87
+ end
88
+
89
+ # Creates a hash with posts separated by year
90
+ def to_year_hash
91
+ r = Hash.new {|h, k| h[k] = []}
92
+ @archive.each do |year, m|
93
+ m.each do |month, d|
94
+ d.each do |date, p|
95
+ r[year] << p
96
+ r[year].flatten!
97
+ end
98
+ end
99
+ end
100
+ r
101
+ end
102
+
103
+ ##
104
+ # Writes the archive pages
105
+ def write
106
+ self.write_years if @site.layouts['archive_year']
107
+ self.write_months if @site.layouts['archive_month']
108
+ self.write_dates if @site.layouts['archive_date']
109
+ end
110
+
111
+ def write_years
112
+ years = self.to_year_hash
113
+ years.each do |year, posts|
114
+ write_path = File.join( @config[:root], year, 'index.html' )
115
+ # date should give the full date, as a Time object!! and the others
116
+ t = Time.parse("#{year}/01/01")
117
+ payload = {:name => 'archive', :payload => {'date' => t, 'posts' => years[year]} }
118
+ page = Gen.new( write_path, @site, payload )
119
+ page.layout = @site.layouts['archive_year']
120
+
121
+ page.render
122
+ page.write
123
+ end
124
+ end
125
+
126
+ def write_months
127
+ months = self.to_month_hash
128
+ months.each do |year, posts|
129
+ posts.each do |month, posts|
130
+ write_path = File.join( @config[:root], year, month, 'index.html' )
131
+ t = Time.parse("#{year}/#{month}/01")
132
+ payload = {:name => 'archive', :payload => {'date' => t, 'posts' => months[year][month]} }
133
+ page = Gen.new( write_path, @site, payload )
134
+ page.layout = @site.layouts['archive_month']
135
+
136
+ page.render
137
+ page.write
138
+ end
139
+ end
140
+ end
141
+
142
+ def write_dates
143
+ dates = self.to_date_hash
144
+ dates.each do |year, posts|
145
+ posts.each do |month, posts|
146
+ posts.each do |date, posts|
147
+ write_path = File.join( @config[:root], year, month, date, 'index.html' )
148
+ t = Time.parse("#{year}/#{month}/#{date}")
149
+ payload = {:name => 'archive', :payload => {'date' => t, 'posts' => dates[year][month][date]} }
150
+ page = Gen.new( write_path, @site, payload )
151
+ page.layout = @site.layouts['archive_date']
152
+
153
+ page.render
154
+ page.write
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ end
161
+ end
@@ -11,10 +11,15 @@ module Henshin
11
11
  def to_hash
12
12
  hash = {
13
13
  'name' => @name,
14
- 'posts' => @posts.collect {|i| i.to_hash}
14
+ 'posts' => @posts.sort.collect {|i| i.to_hash},
15
+ 'url' => self.url
15
16
  }
16
17
  end
17
18
 
19
+ def url
20
+ "/categories/#{@name.slugify}/"
21
+ end
22
+
18
23
 
19
24
  def inspect
20
25
  "#<Category:#{@name}>"
@@ -25,7 +25,7 @@ def Exception.ignoring_exceptions
25
25
  begin
26
26
  yield
27
27
  rescue Exception => e
28
- STDERR.puts e.message
28
+ STDERR.puts e
29
29
  end
30
30
  end
31
31
 
@@ -58,19 +58,10 @@ class String
58
58
  slug
59
59
  end
60
60
 
61
- # Capitalizes the string using Gruber's guidelines
62
- def titlize
63
- self
64
- end
65
-
66
61
  # Gets the extension from a string
67
62
  def extension
68
63
  parts = self.split('.')
69
- if parts.size == 2
70
- return parts[1]
71
- elsif parts.size == 3
72
- return parts[2]
73
- end
64
+ parts[parts.size-1]
74
65
  end
75
66
 
76
67
  # Gets the directory from a string
@@ -84,46 +75,4 @@ class String
84
75
  self.dup.gsub(/([a-zA-Z0-9_-]+\/)/, '')
85
76
  end
86
77
 
87
-
88
-
89
- # Methods to determine whether the file at the path is a post, layout, gen or static
90
-
91
- # @param [Hash] config
92
- # @return [Bool]
93
- # @todo see #ignored?
94
- def static?( config )
95
- !( self.layout? || self.post? || self.gen?(config) || self.ignored?(config) )
96
- end
97
-
98
- # @return [Bool]
99
- def layout?
100
- self.include? 'layouts/'
101
- end
102
-
103
- # @return [Bool]
104
- def post?
105
- self.include? 'posts/'
106
- end
107
-
108
- # @param [Hash] config
109
- # @return [Bool]
110
- # @todo see #ignored?
111
- def gen?( config )
112
- return true if config[:plugins][:generators].has_key? self.extension
113
- return true if File.open(self, "r").read(3) == "---"
114
- false
115
- end
116
-
117
- # @param [Hash] config
118
- # @return [Bool]
119
- # @todo Find a way around having to pass the config in
120
- def ignored?( config )
121
- ignored = ['/options.yaml'] + config[:exclude]
122
- ignored.collect! {|i| File.join(config[:root], i)}
123
- ignored.each do |i|
124
- return true if self.include? i
125
- end
126
- false
127
- end
128
-
129
78
  end
@@ -3,7 +3,7 @@ module Henshin
3
3
  # This is the main class for all pages, posts, sass, etc, that need to be run through a plugin
4
4
  class Gen
5
5
 
6
- attr_accessor :path, :extension, :content, :layout, :date, :title
6
+ attr_accessor :path, :extension, :content, :layout, :title
7
7
  attr_accessor :site, :config, :renderer, :data, :output
8
8
 
9
9
  def initialize( path, site, data=nil )
@@ -40,7 +40,6 @@ module Henshin
40
40
  def override( override )
41
41
  @title = override[:title] if override[:title]
42
42
  @layout = @site.layouts[ override[:layout] ] if override[:layout]
43
- @date = Time.parse( override[:date].to_s ) if override[:date]
44
43
  end
45
44
 
46
45
 
@@ -48,18 +47,26 @@ module Henshin
48
47
  # Renders the files content
49
48
  def render
50
49
  ignore_layout = false
50
+ plugins = []
51
+
52
+ config[:plugins][:generators].each do |k, v|
53
+ if k == @extension || k == '*'
54
+ plugins << v
55
+ end
56
+ end
57
+ plugins.sort!
51
58
 
52
- if config[:plugins][:generators].has_key? @extension
53
- plugin = config[:plugins][:generators][@extension]
54
- @content = plugin.generate( @content )
55
- @output = plugin.extensions[:output]
59
+ plugins.each do |plugin|
60
+ @content = plugin.generate(@content)
61
+ @output = plugin.extensions[:output] if plugin.extensions[:output]
56
62
  ignore_layout = true if plugin.config[:ignore_layouts]
57
63
  end
58
-
64
+
59
65
  @layout ||= site.layouts[ site.config[:layout] ]
60
66
  unless ignore_layout || @layout.nil?
61
67
  config[:plugins][:layout_parsers].each do |plugin|
62
68
  @content = plugin.generate( @layout, self.payload )
69
+ @content = plugin.generate( @content, self.payload )
63
70
  end
64
71
  end
65
72
 
@@ -87,7 +94,6 @@ module Henshin
87
94
  'title' => @title,
88
95
  'permalink' => self.permalink,
89
96
  'url' => self.url,
90
- 'date' => @date,
91
97
  'content' => @content
92
98
  }
93
99
  end
@@ -122,13 +128,8 @@ module Henshin
122
128
 
123
129
 
124
130
  # Needed to sort the posts by date, newest first
125
- def <=>( val )
126
- s = self.date <=> val.date
127
- if s == 0
128
- return self.permalink <=> val.permalink
129
- else
130
- return -1 * s
131
- end
131
+ def <=>( other )
132
+ self.permalink <=> other.permalink
132
133
  end
133
134
 
134
135
  def inspect
@@ -8,20 +8,33 @@ module Henshin
8
8
 
9
9
  attr_accessor :extensions, :config
10
10
 
11
+ # Defaults = {}
12
+
11
13
  def initialize
12
14
  # inputs are the file types it will take
13
15
  # output should be the type it creates
14
16
  @extensions = {:input => [],
15
17
  :output => ''}
16
- @config = {}
17
18
  end
18
19
 
19
- # def configure( override )
20
- # setup the plugin
21
- # end
20
+ def configure( override )
21
+ if Defaults
22
+ if override
23
+ @config = Defaults.merge(override)
24
+ else
25
+ @config = Defaults
26
+ end
27
+ elsif override
28
+ @config = override
29
+ end
30
+ end
31
+
32
+ def <=>(other)
33
+ self.priority <=> other.priority
34
+ end
22
35
 
23
36
  # Uncomment to have the plugin loaded
24
- # Henshin.register! self
37
+ # Henshin.register! self, :standard_plugin
25
38
  end
26
39
 
27
40
  class Generator < StandardPlugin
@@ -32,7 +45,7 @@ module Henshin
32
45
  end
33
46
 
34
47
  # Uncomment to have the plugin loaded
35
- # Henshin.register! self
48
+ # Henshin.register! self, :generator
36
49
  end
37
50
 
38
51
  class LayoutParser < StandardPlugin
@@ -44,7 +57,7 @@ module Henshin
44
57
  end
45
58
 
46
59
  # Uncomment to have the plugin loaded
47
- # Henshin.register! self
60
+ # Henshin.register! self, :generator
48
61
  end
49
62
 
50
63
  end
@@ -0,0 +1,31 @@
1
+ require 'henshin/plugin'
2
+ require 'simplabs/highlight'
3
+
4
+ class HighlightPlugin < Henshin::Generator
5
+
6
+ attr_accessor :priority, :config, :extensions
7
+
8
+ def initialize
9
+ @extensions = {:input => ['*']}
10
+ @config = {}
11
+ @priority = 1
12
+ end
13
+
14
+ def configure( override )
15
+ @config.merge!(override) if override
16
+ end
17
+
18
+ def generate( content )
19
+ content =~ /(\$highlight)\s+(.+)((\n.*)+)(\$end)/
20
+ if $1
21
+ lang = $2.to_sym
22
+ code = $3[1..-1] # removes first new line
23
+ insert = '<pre><code>' + Simplabs::Highlight.highlight(lang, code) + '</code></pre>'
24
+ content.gsub(/(\$highlight.*\$end)/m, insert)
25
+ else
26
+ content
27
+ end
28
+ end
29
+
30
+ Henshin.register! self
31
+ end
@@ -3,27 +3,61 @@ require 'liquid'
3
3
 
4
4
  class LiquidPlugin < Henshin::LayoutParser
5
5
 
6
- attr_accessor :extensions
6
+ attr_accessor :config
7
7
 
8
8
  def initialize
9
- @extensions = {:input => [],
10
- :output => ''}
9
+ @config = {}
10
+ end
11
+
12
+ def configure( override )
13
+ @config.merge!(override) if override
11
14
  end
12
15
 
13
16
  def generate( layout, data )
14
- t = Liquid::Template.parse( read(layout) )
15
- t.render(data)
17
+ reg = {:include_dir => @config['include_dir']}
18
+ Liquid::Template.parse(layout).render(data, :registers => reg)
19
+ end
20
+
21
+ module Filters
22
+ def date_to_string(dt)
23
+ dt.strftime "%d %b %Y"
24
+ end
25
+
26
+ def date_to_long(dt)
27
+ dt.strftime "%d %B %Y at %H:%M"
28
+ end
29
+
30
+ def time_to_string(dt)
31
+ dt.strtime "%H:%M"
32
+ end
33
+
34
+ def titlecase(str)
35
+ str.upcase
36
+ end
37
+
38
+ def escape(str)
39
+ CGI::escape str
40
+ end
41
+
42
+ def escape_html(str)
43
+ CGI::escapeHTML str
44
+ end
16
45
  end
46
+ Liquid::Template.register_filter(Filters)
17
47
 
18
- # returns the layout as a string
19
- def read( file )
20
- f = File.open(file, "r")
21
- r = ""
22
- f.each do |l|
23
- r << l
24
- end
25
- r
48
+ class Include < Liquid::Tag
49
+ def initialize(tag_name, file, tokens)
50
+ super
51
+ @file = file.strip
52
+ end
53
+
54
+ def render(context)
55
+ include = File.join(context.registers[:include_dir], @file)
56
+ File.open(include, 'r') {|f| f.read}
57
+ end
26
58
  end
59
+ Liquid::Template.register_tag('include', Include)
27
60
 
28
- Henshin.register! self
61
+ Henshin.register! self, :liquid
29
62
  end
63
+