hamlet 0.1

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 (71) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +25 -0
  3. data/LICENSE +21 -0
  4. data/README.md +52 -0
  5. data/Rakefile +57 -0
  6. data/bin/hamletrb +7 -0
  7. data/extra/slim-mode.el +409 -0
  8. data/extra/test.hamlet +50 -0
  9. data/hamlet.gemspec +36 -0
  10. data/lib/hamlet.rb +7 -0
  11. data/lib/hamlet/engine.rb +3 -0
  12. data/lib/hamlet/parser.rb +147 -0
  13. data/lib/hamlet/template.rb +19 -0
  14. data/test/rails/Rakefile +7 -0
  15. data/test/rails/app/controllers/application_controller.rb +3 -0
  16. data/test/rails/app/controllers/parents_controller.rb +84 -0
  17. data/test/rails/app/controllers/slim_controller.rb +32 -0
  18. data/test/rails/app/helpers/application_helper.rb +2 -0
  19. data/test/rails/app/models/child.rb +3 -0
  20. data/test/rails/app/models/parent.rb +4 -0
  21. data/test/rails/app/views/layouts/application.html.slim +10 -0
  22. data/test/rails/app/views/parents/_form.html.slim +7 -0
  23. data/test/rails/app/views/parents/edit.html.slim +1 -0
  24. data/test/rails/app/views/parents/new.html.slim +1 -0
  25. data/test/rails/app/views/parents/show.html.slim +5 -0
  26. data/test/rails/app/views/slim/_partial.html.slim +1 -0
  27. data/test/rails/app/views/slim/content_for.html.slim +7 -0
  28. data/test/rails/app/views/slim/erb.html.erb +1 -0
  29. data/test/rails/app/views/slim/integers.html.slim +1 -0
  30. data/test/rails/app/views/slim/nil.html.slim +1 -0
  31. data/test/rails/app/views/slim/no_layout.html.slim +1 -0
  32. data/test/rails/app/views/slim/normal.html.slim +1 -0
  33. data/test/rails/app/views/slim/partial.html.slim +2 -0
  34. data/test/rails/app/views/slim/variables.html.slim +1 -0
  35. data/test/rails/config.ru +4 -0
  36. data/test/rails/config/application.rb +45 -0
  37. data/test/rails/config/boot.rb +10 -0
  38. data/test/rails/config/database.yml +4 -0
  39. data/test/rails/config/environment.rb +5 -0
  40. data/test/rails/config/environments/development.rb +26 -0
  41. data/test/rails/config/environments/production.rb +49 -0
  42. data/test/rails/config/environments/test.rb +35 -0
  43. data/test/rails/config/initializers/backtrace_silencers.rb +7 -0
  44. data/test/rails/config/initializers/inflections.rb +10 -0
  45. data/test/rails/config/initializers/mime_types.rb +5 -0
  46. data/test/rails/config/initializers/secret_token.rb +7 -0
  47. data/test/rails/config/initializers/session_store.rb +8 -0
  48. data/test/rails/config/locales/en.yml +5 -0
  49. data/test/rails/config/routes.rb +60 -0
  50. data/test/rails/db/migrate/20101220223037_parents_and_children.rb +17 -0
  51. data/test/rails/script/rails +6 -0
  52. data/test/rails/test/helper.rb +10 -0
  53. data/test/rails/test/test_slim.rb +77 -0
  54. data/test/slim/helper.rb +200 -0
  55. data/test/slim/test_chain_manipulation.rb +42 -0
  56. data/test/slim/test_code_blocks.rb +68 -0
  57. data/test/slim/test_code_escaping.rb +53 -0
  58. data/test/slim/test_code_evaluation.rb +281 -0
  59. data/test/slim/test_code_output.rb +159 -0
  60. data/test/slim/test_code_structure.rb +95 -0
  61. data/test/slim/test_embedded_engines.rb +141 -0
  62. data/test/slim/test_html_escaping.rb +40 -0
  63. data/test/slim/test_html_structure.rb +438 -0
  64. data/test/slim/test_parser_errors.rb +107 -0
  65. data/test/slim/test_pretty.rb +75 -0
  66. data/test/slim/test_ruby_errors.rb +187 -0
  67. data/test/slim/test_sections.rb +90 -0
  68. data/test/slim/test_slim_template.rb +118 -0
  69. data/test/slim/test_text_interpolation.rb +78 -0
  70. data/test/slim/test_wrapper.rb +39 -0
  71. metadata +230 -0
data/extra/test.hamlet ADDED
@@ -0,0 +1,50 @@
1
+ <doctype html
2
+
3
+ <html
4
+ <head
5
+ <title Slim Test
6
+ <meta name="keywords" content="slim, syntax"
7
+
8
+ <javascript:
9
+ $(function() {
10
+ alert('Hello World');
11
+ });
12
+
13
+ <haml:
14
+ #someid.someclass{:this => 'test'} Content in haml
15
+
16
+ <erb:
17
+ <%= some_method(@request) %>
18
+
19
+ <body
20
+ / comment block
21
+ with multiple lines
22
+ This is another line
23
+ <h1 = @page_title
24
+ <p#notice.message
25
+ | Welcome to the the syntax test.
26
+ This file is to exercise the various markup.
27
+ This is another line
28
+ - unless @users.empty?
29
+ <table
30
+ - for user in users do
31
+ <tr
32
+ <td.user id=some_ruby('ere', @rme) data-test="some text #{with @ruby}" = @post.name
33
+ - else
34
+ <p There are no users.
35
+
36
+ / Single comment line
37
+ #content Hello #{@user.name}! Welcome to the test page!
38
+ Try out Slim!
39
+
40
+ = function_with_many_parameters(:a, @variable, :option => 1)
41
+
42
+ <p.text
43
+ ' Another text block
44
+ with multiple lines
45
+
46
+ = link_to('Test', @site)
47
+
48
+ .text#footer
49
+ ' Footer text block
50
+ with multiple lines
data/hamlet.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #require File.dirname(__FILE__) + '/lib/hamlet/version'
3
+ require 'date'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'hamlet'
7
+ s.version = 0.1
8
+ s.date = Date.today.to_s
9
+ s.authors = ['Greg Weber']
10
+ s.email = ['greg@gregweber.info']
11
+ s.summary = 'Hamlet is a DRY HTML template language.'
12
+ s.description = 'Hamlet is a template language whose goal is reduce HTML syntax to the essential parts.'
13
+ s.homepage = 'http://github.com/gregwebs/hamlet.rb'
14
+ s.extra_rdoc_files = %w(README.md)
15
+ s.rdoc_options = %w(--charset=UTF-8)
16
+ s.rubyforge_project = s.name
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = %w(lib)
21
+
22
+ s.add_dependency('slim', ['~> 1.0'])
23
+
24
+ s.add_development_dependency('rake', ['>= 0.8.7'])
25
+ s.add_development_dependency('sass', ['>= 3.1.0'])
26
+ s.add_development_dependency('minitest', ['>= 0'])
27
+ s.add_development_dependency('kramdown', ['>= 0'])
28
+ s.add_development_dependency('yard', ['>= 0'])
29
+ s.add_development_dependency('creole', ['>= 0'])
30
+ s.add_development_dependency('builder', ['>= 0'])
31
+ s.add_development_dependency('pry', ['>= 0'])
32
+
33
+ unless defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
34
+ s.add_development_dependency('rcov', ['>= 0'])
35
+ end
36
+ end
data/lib/hamlet.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+
3
+ require 'slim'
4
+
5
+ require 'hamlet/parser'
6
+ require 'hamlet/engine'
7
+ require 'hamlet/template'
@@ -0,0 +1,3 @@
1
+ class Hamlet::Engine < Slim::Engine
2
+ replace Slim::Parser, Hamlet::Parser
3
+ end
@@ -0,0 +1,147 @@
1
+ require 'slim/parser'
2
+
3
+ # @api private
4
+ module Hamlet
5
+ class Parser < Slim::Parser
6
+ private
7
+
8
+ def parse_line_indicators
9
+ case @line
10
+ when /\A\//
11
+ # Found a comment block.
12
+ if @line =~ %r{\A/!( ?)(.*)\Z}
13
+ # HTML comment
14
+ block = [:multi]
15
+ @stacks.last << [:html, :comment, block]
16
+ @stacks << block
17
+ @stacks.last << [:slim, :interpolate, $2] unless $2.empty?
18
+ parse_text_block($2.empty? ? nil : @indents.last + $1.size + 2)
19
+ elsif @line =~ %r{\A/\[\s*(.*?)\s*\]\s*\Z}
20
+ # HTML conditional comment
21
+ block = [:multi]
22
+ @stacks.last << [:slim, :condcomment, $1, block]
23
+ @stacks << block
24
+ else
25
+ # Slim comment
26
+ parse_comment_block
27
+ end
28
+ when /\A-/
29
+ # Found a code block.
30
+ # We expect the line to be broken or the next line to be indented.
31
+ block = [:multi]
32
+ @line.slice!(0)
33
+ @stacks.last << [:slim, :control, parse_broken_line, block]
34
+ @stacks << block
35
+ when /\A=/
36
+ # Found an output block.
37
+ # We expect the line to be broken or the next line to be indented.
38
+ @line =~ /\A=(=?)('?)/
39
+ @line = $'
40
+ block = [:multi]
41
+ @stacks.last << [:slim, :output, $1.empty?, parse_broken_line, block]
42
+ @stacks.last << [:static, ' '] unless $2.empty?
43
+ @stacks << block
44
+ when /\A<(\w+):\s*\Z/
45
+ # Embedded template detected. It is treated as block.
46
+ block = [:multi]
47
+ @stacks.last << [:newline] << [:slim, :embedded, $1, block]
48
+ @stacks << block
49
+ parse_text_block
50
+ return # Don't append newline, this has already been done before
51
+ when /\Adoctype\s+/i
52
+ # Found doctype declaration
53
+ @stacks.last << [:html, :doctype, $'.strip]
54
+ when /\A<([#\.]|\w[:\w-]*)/
55
+ # Found a HTML tag.
56
+ parse_tag($1)
57
+ when /\A(> *)?(.*)?\Z/
58
+ # Found a text block.
59
+ trailing_ws = !$1
60
+ @stacks.last << [:slim, :interpolate, $2] unless $2.empty?
61
+ parse_text_block($2.empty? ? nil : @indents.last + $1.to_s.size)
62
+ @stacks.last << [:static, ' '] if trailing_ws
63
+ else
64
+ syntax_error! 'Unknown line indicator'
65
+ end
66
+ @stacks.last << [:newline]
67
+ end
68
+
69
+ def parse_comment_block
70
+ while !@lines.empty? && (@lines.first =~ /\A\s*\Z/ || get_indent(@lines.first) > @indents.last)
71
+ next_line
72
+ @stacks.last << [:newline]
73
+ end
74
+ end
75
+
76
+ def parse_text_block(text_indent = nil)
77
+ empty_lines = 0
78
+ until @lines.empty?
79
+ if @lines.first =~ /\A\s*\Z/
80
+ next_line
81
+ @stacks.last << [:newline]
82
+ empty_lines += 1 if text_indent
83
+ else
84
+ indent = get_indent(@lines.first)
85
+ break if indent <= @indents.last
86
+
87
+ if empty_lines > 0
88
+ @stacks.last << [:slim, :interpolate, "\n" * empty_lines]
89
+ empty_lines = 0
90
+ end
91
+
92
+ next_line
93
+
94
+ # The text block lines must be at least indented
95
+ # as deep as the first line.
96
+ if text_indent && indent < text_indent
97
+ @line.lstrip!
98
+ syntax_error!('Unexpected text indentation')
99
+ end
100
+
101
+ @line.slice!(0, text_indent || indent)
102
+ @stacks.last << [:slim, :interpolate, (text_indent ? "\n" : '') + @line] << [:newline]
103
+
104
+ # The indentation of first line of the text block
105
+ # determines the text base indentation.
106
+ text_indent ||= indent
107
+ end
108
+ end
109
+ end
110
+
111
+ def parse_tag(tag)
112
+ @line.slice!(0,1) # get rid of leading '<'
113
+ if tag == '#' || tag == '.'
114
+ tag = options[:default_tag]
115
+ else
116
+ @line.slice!(0, tag.size)
117
+ end
118
+
119
+ tag = [:html, :tag, tag, parse_attributes]
120
+ @stacks.last << tag
121
+
122
+ case @line
123
+ when /\A\s*>?=(=?)('?)/
124
+ # Handle output code
125
+ block = [:multi]
126
+ @line = $'
127
+ content = [:slim, :output, $1 != '=', parse_broken_line, block]
128
+ tag << content
129
+ @stacks.last << [:static, ' '] unless $2.empty?
130
+ @stacks << block
131
+ when /\A\s*\//
132
+ # Closed tag. Do nothing
133
+ when /\A\s*>?\s*\Z/
134
+ # Empty content
135
+ content = [:multi]
136
+ tag << content
137
+ @stacks << content
138
+ when /\A( ?)>?(.*)\Z/
139
+ # Text content
140
+ content = [:multi, [:slim, :interpolate, $2]]
141
+ tag << content
142
+ @stacks << content
143
+ parse_text_block(@orig_line.size - @line.size + $1.size)
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,19 @@
1
+ module Hamlet
2
+ # Tilt template implementation for Hamlet
3
+ # @api public
4
+ Template = Temple::Templates::Tilt(Hamlet::Engine, :register_as => :hamlet)
5
+
6
+ if Object.const_defined?(:Rails)
7
+ # Rails template implementation for Hamlet
8
+ # @api public
9
+ RailsTemplate = Temple::Templates::Rails(Hamlet::Engine,
10
+ :register_as => :hamlet,
11
+ # Use rails-specific generator. This is necessary
12
+ # to support block capturing and streaming.
13
+ :generator => Temple::Generators::RailsOutputBuffer,
14
+ # Disable the internal hamlet capturing.
15
+ # Rails takes care of the capturing by itself.
16
+ :disable_capture => true,
17
+ :streaming => Object.const_defined?(:Fiber))
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+ require 'rake'
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,84 @@
1
+ class ParentsController < ApplicationController
2
+ # GET /parents
3
+ # GET /parents.xml
4
+ def index
5
+ @parents = Parent.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.xml { render :xml => @parents }
10
+ end
11
+ end
12
+
13
+ # GET /parents/1
14
+ # GET /parents/1.xml
15
+ def show
16
+ @parent = Parent.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.xml { render :xml => @parent }
21
+ end
22
+ end
23
+
24
+ # GET /parents/new
25
+ # GET /parents/new.xml
26
+ def new
27
+ @parent = Parent.new
28
+ @parent.children.build
29
+
30
+ respond_to do |format|
31
+ format.html # new.html.erb
32
+ format.xml { render :xml => @parent }
33
+ end
34
+ end
35
+
36
+ # GET /parents/1/edit
37
+ def edit
38
+ @parent = Parent.find(params[:id])
39
+ end
40
+
41
+ # POST /parents
42
+ # POST /parents.xml
43
+ def create
44
+ @parent = Parent.new(params[:parent])
45
+
46
+ respond_to do |format|
47
+ if @parent.save
48
+ format.html { redirect_to(@parent, :notice => 'Parent was successfully created.') }
49
+ format.xml { render :xml => @parent, :status => :created, :location => @parent }
50
+ else
51
+ format.html { render :action => "new" }
52
+ format.xml { render :xml => @parent.errors, :status => :unprocessable_entity }
53
+ end
54
+ end
55
+ end
56
+
57
+ # PUT /parents/1
58
+ # PUT /parents/1.xml
59
+ def update
60
+ @parent = Parent.find(params[:id])
61
+
62
+ respond_to do |format|
63
+ if @parent.update_attributes(params[:parent])
64
+ format.html { redirect_to(@parent, :notice => 'Parent was successfully updated.') }
65
+ format.xml { head :ok }
66
+ else
67
+ format.html { render :action => "edit" }
68
+ format.xml { render :xml => @parent.errors, :status => :unprocessable_entity }
69
+ end
70
+ end
71
+ end
72
+
73
+ # DELETE /parents/1
74
+ # DELETE /parents/1.xml
75
+ def destroy
76
+ @parent = Parent.find(params[:id])
77
+ @parent.destroy
78
+
79
+ respond_to do |format|
80
+ format.html { redirect_to(parents_url) }
81
+ format.xml { head :ok }
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,32 @@
1
+ class SlimController < ApplicationController
2
+ def normal
3
+ end
4
+
5
+ def no_layout
6
+ render :layout => false
7
+ end
8
+
9
+ def variables
10
+ @hello = "Hello Slim with variables!"
11
+ end
12
+
13
+ def partial
14
+ end
15
+
16
+ def streaming
17
+ @hello = "Hello Streaming!"
18
+ render :content_for, :stream => true
19
+ end
20
+
21
+ def integers
22
+ @integer = 1337
23
+ end
24
+
25
+ def nil
26
+ @nil = nil
27
+ end
28
+
29
+ def content_for
30
+ @hello = "Hello Slim!"
31
+ end
32
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,3 @@
1
+ class Child < ActiveRecord::Base
2
+ belongs_to :parent
3
+ end
@@ -0,0 +1,4 @@
1
+ class Parent < ActiveRecord::Base
2
+ has_many :children
3
+ accepts_nested_attributes_for :children, :allow_destroy => true
4
+ end
@@ -0,0 +1,10 @@
1
+ doctype html
2
+
3
+ html
4
+ head
5
+ title Dummy
6
+ = csrf_meta_tag
7
+
8
+ body
9
+ = yield :page_heading
10
+ .content= yield
@@ -0,0 +1,7 @@
1
+ = form_for @parent, :html => {:multipart => true} do |f|
2
+ h1 Parent
3
+ = f.text_field :name
4
+ h2 Children
5
+ ul
6
+ = f.fields_for :children do |c|
7
+ li= c.text_field :name
@@ -0,0 +1 @@
1
+ = render "form"
@@ -0,0 +1 @@
1
+ = render "form"