henshin 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+