non-haml 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ module Color
2
+ COLORS = {clear: 0, red: 31, green: 32, yellow: 33, blue: 34, gray: 30, grey: 30}
3
+ def self.method_missing(color_name, *args)
4
+ if args.first.is_a? String
5
+ color(color_name) + args.first + color(:clear)
6
+ else
7
+ color(color_name) + args.first.inspect + color(:clear)
8
+ end
9
+ end
10
+
11
+ def self.color(color)
12
+ "\e[#{COLORS[color.to_sym]}m"
13
+ end
14
+ end
@@ -0,0 +1,204 @@
1
+ # Simple line-wise parser for converting special files into slightly-enhanced
2
+ # files. No need for anything too complicated like a full-on grammar.
3
+ # Similar syntax to haml.
4
+
5
+ # Example usage:
6
+ # require 'non-haml'
7
+ # NonHaml.generate 'output/source.c', 'source.c', binding
8
+
9
+ module NonHaml
10
+ class << self
11
+ attr_accessor :last_ok_line, :out, :base_dir
12
+
13
+ def concat spaces=nil, text=nil
14
+ if spaces.nil? and text.nil?
15
+ self.out << "\n"
16
+ else
17
+ text.to_s.lines do |l|
18
+ self.out << "#{' '*spaces}#{l.rstrip}\n"
19
+ end
20
+ end
21
+ end
22
+
23
+ def generate out_name, in_name, context, base_dir='./', verbose=false
24
+ NonHamlParser.new.generate out_name, in_name, context, base_dir, verbose
25
+ end
26
+
27
+ def filename
28
+ # Retrieves the current filename.
29
+ @filenames.last
30
+ end
31
+
32
+ def push_filename new_name
33
+ @filenames ||= []
34
+ @filenames << new_name
35
+ end
36
+
37
+ def pop_filename
38
+ @filenames.pop
39
+ end
40
+
41
+ def current_filename
42
+ "#{base_dir}#{NonHaml.filename}"
43
+ end
44
+ end
45
+
46
+ class IndentError < StandardError
47
+ end
48
+
49
+ class ParseError < StandardError
50
+ end
51
+
52
+ class NonHamlParser
53
+ def parse text, base_control_indent=0, base_indent=0
54
+ @s = ""
55
+ def store text
56
+ @s << "#{text}\n"
57
+ end
58
+
59
+ # Number of indents at the start of blocks.
60
+ @block_starts = []
61
+ @statements = []
62
+ @base_control_indent = base_control_indent
63
+ def control_indent
64
+ ' ' * (@block_starts.length + @base_control_indent)
65
+ end
66
+
67
+ def dedent indent, suppress_end=false
68
+ dedented = false
69
+ @block_starts.reverse.take_while{|x| x >= indent}.each do |x|
70
+ # Close some blocks to get back to the right indentation level.
71
+ @block_starts.pop
72
+ unless suppress_end and %w{if elsif else}.include?(@statements.pop) and x == indent
73
+ store control_indent + 'end'
74
+ end
75
+ dedented = true # return status so we know whether to skip a blank line.
76
+ end
77
+ dedented
78
+ end
79
+
80
+ text.lines.with_index do |line,i|
81
+ line.rstrip!
82
+
83
+ line =~ /^( *)(.*)$/
84
+ indent, line = $1.length, $2
85
+ indent += base_indent
86
+
87
+ if (line =~ /^- *((if|unless|for|elsif|else)\b.*)$/) or (line =~ /^- *(.*\bdo\b *(|.*|)?)$/)
88
+ # Entering a block.
89
+
90
+ if %w{elsif else}.include? $2
91
+ store control_indent + "NonHaml.last_ok_line = #{i}"
92
+ dedent indent, %w{elsif else}.include?($2)
93
+ else
94
+ dedent indent, %w{elsif else}.include?($2)
95
+ store control_indent + "NonHaml.last_ok_line = #{i}"
96
+ end
97
+
98
+ store control_indent + $1
99
+ @block_starts << indent
100
+ @statements << $2
101
+ # Output should have same indent as block.
102
+ concat_indent = indent
103
+ elsif line =~ /= ?non_haml ['"](.*)['"]/
104
+ store control_indent + "NonHaml.last_ok_line = #{i}"
105
+ file = NonHaml.base_dir + $1
106
+ if File.readable? file
107
+ store control_indent + "NonHaml.push_filename '#{$1}'"
108
+ @s += parse open(file).read, control_indent.length, indent
109
+ else
110
+ store control_indent + "raise Errno::ENOENT, '\"#{$1}\"'"
111
+ end
112
+ store control_indent + "NonHaml.pop_filename"
113
+ elsif line.strip.length.zero?
114
+ # Blank line. Output and move on. Don't change indent. Only do this
115
+ # for if blocks though, so 'if false' doesn't generate optional blank
116
+ # line and 'if true' does.
117
+ #if @statements.last == 'if' or @statements.empty?
118
+ # XXX disabled temporarily because it sucked.
119
+ store control_indent + "NonHaml.last_ok_line = #{i}"
120
+ #if @statements.empty?
121
+ store "#{control_indent}NonHaml.concat"
122
+ #end
123
+ else
124
+ dedented = dedent indent
125
+ store control_indent + "NonHaml.last_ok_line = #{i}"
126
+
127
+ # Now deal with whatever we have left.
128
+ if line =~ /^- *(.*)$/
129
+ # Generic Ruby statement that isn't entering/leaving a block.
130
+ store control_indent + $1
131
+ elsif line =~ /^= *(.*)$/
132
+ # Concatenate this for evaluation.
133
+ target_indent = indent - control_indent.length
134
+ # Deal with blank lines.
135
+ content = $1
136
+ content = '""' if content.empty?
137
+ store "#{control_indent}NonHaml.concat(#{target_indent}, (#{content}))"
138
+ elsif dedented and line.strip.empty?
139
+ puts 'skipping'
140
+ # Skip up to one blank line after dedenting.
141
+ next
142
+ else
143
+ # Concatenate this for output.
144
+ target_indent = indent - control_indent.length
145
+ # Replace #{} blocks, but completely quote the rest.
146
+ # TODO clean up more nicely if we fail here!!!
147
+ to_sub = []
148
+ line.gsub!('%', '%%')
149
+ line.gsub!(/#\{(.*?)\}/){to_sub << $1; '%s'}
150
+ if to_sub.empty?
151
+ # Must do pretend substitutions to get around %% characters.
152
+ subst = " % []"
153
+ else
154
+ # Include brackets around all quantities, so bracket-free
155
+ # functions get the right arguments.
156
+ subst = " % [#{to_sub.map{|x| "(#{x})"}.join ', '}]"
157
+ end
158
+ store "#{control_indent}NonHaml.concat #{target_indent}, (%q##{line.gsub('#', '\\#')}##{subst})"
159
+ end
160
+ end
161
+ end
162
+ dedent 0
163
+ @s
164
+ end
165
+
166
+ def generate out_name, in_name, context, base_dir, verbose
167
+ NonHaml.base_dir = base_dir
168
+ NonHaml.out = ""
169
+
170
+ NonHaml.push_filename in_name
171
+
172
+ src = parse open(NonHaml.current_filename).read
173
+ if verbose
174
+ src.lines.each_with_index do |l,i|
175
+ print Color.blue '%3d ' % (i + 1)
176
+ puts l
177
+ end
178
+ end
179
+
180
+ begin
181
+ eval src, context
182
+ rescue Exception => e
183
+ # Interrupt everything, give more info, then dump out the old exception.
184
+ $stderr.puts
185
+ $stderr.puts "in #{NonHaml.current_filename}:"
186
+ $stderr.puts Color.red " #{e.class.name}: #{Color.blue e.to_s}"
187
+ open(NonHaml.current_filename).lines.each_with_index.drop([NonHaml.last_ok_line - 2, 0].max).first(5).each do |line,i|
188
+ if i == NonHaml.last_ok_line
189
+ $stderr.print Color.red ' %3d ' % (i + 1)
190
+ $stderr.print Color.red line
191
+ else
192
+ $stderr.print ' %3d ' % (i + 1)
193
+ $stderr.print line
194
+ end
195
+ end
196
+ raise e
197
+ else
198
+ open(out_name, 'w') do |f|
199
+ f.puts NonHaml.out
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,9 @@
1
+ module NonHaml
2
+ unless const_defined?('VERSION')
3
+ VERSION = "1.0"
4
+ end
5
+
6
+ def self.version
7
+ VERSION
8
+ end
9
+ end
data/lib/non-haml.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "non-haml/version"
2
+ require "non-haml/colorizer"
3
+ require "non-haml/parser"
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: non-haml
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jacob Mattingley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-16 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: HAML-like syntax for non-HTML
15
+ email: jem@ieee.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/non-haml/colorizer.rb
21
+ - lib/non-haml/parser.rb
22
+ - lib/non-haml/version.rb
23
+ - lib/non-haml.rb
24
+ homepage: http://stanford.edu/~jacobm
25
+ licenses: []
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 1.9.2
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 1.8.11
45
+ signing_key:
46
+ specification_version: 3
47
+ summary: HAML-like syntax for non-HTML
48
+ test_files: []
49
+ has_rdoc: