We got nominated! Help us out and vote for GitHub as Best Bootstrapped Startup of 2008. (You can vote once a day.) [ hide ]

public
Rubygem
Fork of nex3/haml
Description: HTML Abstraction Markup Language - A Markup Haiku
Homepage: http://haml.hamptoncatlin.com
Clone URL: git://github.com/chriseppstein/haml.git
nex3 (author)
Fri Dec 07 20:06:36 -0800 2007
commit  c035771d1ce88381e79fe9c8307140bd372f06cf
tree    42f3a3d5f643d196337bd722d16920660ad0352e
parent  131cf788e470bf0ba03acf909909106ea3663b83
haml / lib / haml / exec.rb
100644 287 lines (222 sloc) 7.006 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
require File.dirname(__FILE__) + '/../haml'
require 'optparse'
 
module Haml
  # This module contains code for working with the
  # haml, sass, and haml2html executables,
  # such as command-line parsing stuff.
  # It shouldn't need to be invoked by client code.
  module Exec # :nodoc:
    # A class that encapsulates the executable code
    # for all three executables.
    class Generic # :nodoc:
      def initialize(args)
        @args = args
        @options = {}
      end
 
      def parse!
        begin
          @opts = OptionParser.new(&(method(:set_opts).to_proc))
          @opts.parse!(@args)
 
          process_result
          
          @options
        rescue Exception => e
          raise e if e.is_a? SystemExit
 
          $stderr.print "#{e.class} on line #{get_line e}: " if @options[:trace]
          $stderr.puts e.message
 
          e.backtrace[1..-1].each { |t| $stderr.puts " #{t}" } if @options[:trace]
 
          exit 1
        end
        exit 0
      end
 
      def to_s
        @opts.to_s
      end
 
      protected
 
      def get_line(exception)
        exception.backtrace[0].scan(/:(\d+)/)[0]
      end
      
      private
 
      def set_opts(opts)
        opts.on('-s', '--stdin', :NONE, 'Read input from standard input instead of an input file') do
          @options[:input] = $stdin
        end
 
        opts.on('--trace', :NONE, 'Show a full traceback on error') do
          @options[:trace] = true
        end
 
        opts.on_tail("-?", "-h", "--help", "Show this message") do
          puts opts
          exit
        end
 
        opts.on_tail("-v", "--version", "Print version") do
          puts("Haml " + File.read(File.dirname(__FILE__) + '/../../VERSION'))
          exit
        end
      end
 
      def process_result
        input, output = @options[:input], @options[:output]
        input_file, output_file = if input
                                    [nil, open_file(ARGV[0], 'w')]
                                  else
                                    [open_file(ARGV[0]), open_file(ARGV[1], 'w')]
                                  end
 
        input ||= input_file
        output ||= output_file
        input ||= $stdin
        output ||= $stdout
 
        @options[:input], @options[:output] = input, output
      end
 
      def open_file(filename, flag = 'r')
        return if filename.nil?
        File.open(filename, flag)
      end
    end
 
    # A class encapsulating the executable functionality
    # specific to Haml and Sass.
    class HamlSass < Generic # :nodoc:
      private
 
      def set_opts(opts)
        opts.banner = <<END
Usage: #{@name.downcase} [options] [INPUT] [OUTPUT]
 
Description:
Uses the #{@name} engine to parse the specified template
and outputs the result to the specified file.
 
Options:
END
       
        opts.on('--rails RAILS_DIR', "Install Haml from the Gem to a Rails project") do |dir|
          original_dir = dir
 
          dir = File.join(dir, 'vendor', 'plugins')
 
          unless File.exists?(dir)
            puts "Directory #{dir} doesn't exist"
            exit
          end
 
          dir = File.join(dir, 'haml')
 
          if File.exists?(dir)
            puts "Directory #{dir} already exists."
            exit
          end
 
          begin
            Dir.mkdir(dir)
          rescue SystemCallError
            puts "Cannot create #{dir}"
            exit
          end
 
          File.open(File.join(dir, 'init.rb'), 'w') do |file|
            file.puts "require 'rubygems'"
            file << File.read(File.dirname(__FILE__) + "/../../init.rb")
          end
 
          puts "Haml plugin added to #{original_dir}"
          exit
        end
 
        super
      end
 
      def process_result
        super
        require File.dirname(__FILE__) + "/../#{@name.downcase}"
      end
    end
 
    # A class encapsulating executable functionality
    # specific to Sass.
    class Sass < HamlSass # :nodoc:
      def initialize(args)
        super
        @name = "Sass"
      end
 
      def process_result
        super
        input = @options[:input]
        output = @options[:output]
 
        template = input.read()
        input.close() if input.is_a? File
 
        begin
          result = ::Sass::Engine.new(template).render
        rescue ::Sass::SyntaxError => e
          raise e if @options[:trace]
          raise "Syntax error on line #{get_line e}: #{e.message}"
        end
 
        output.write(result)
        output.close() if output.is_a? File
      end
    end
 
    # A class encapsulating executable functionality
    # specific to Haml.
    class Haml < HamlSass # :nodoc:
      def initialize(args)
        super
        @name = "Haml"
      end
 
      def process_result
        super
        input = @options[:input]
        output = @options[:output]
 
        template = input.read()
        input.close() if input.is_a? File
 
        begin
          result = ::Haml::Engine.new(template).to_html
        rescue Exception => e
          raise e if @options[:trace]
 
          case e
          when ::Haml::SyntaxError: raise "Syntax error on line #{get_line e}: #{e.message}"
          when ::Haml::HamlError: raise "Haml error on line #{get_line e}: #{e.message}"
          else raise "Exception on line #{get_line e}: #{e.message}\n Use --trace for backtrace."
          end
        end
 
        output.write(result)
        output.close() if output.is_a? File
      end
    end
 
    # A class encapsulating executable functionality
    # specific to the html2haml executable.
    class HTML2Haml < Generic # :nodoc:
      def initialize(args)
        super
 
        @module_opts = {}
 
        begin
          require 'haml/html'
        rescue LoadError => err
          dep = err.message.scan(/^no such file to load -- (.*)/)[0]
          puts "Required dependency #{dep} not found!"
          exit 1
        end
      end
 
      def set_opts(opts)
        opts.banner = <<END
Usage: html2haml [options] [INPUT] [OUTPUT]
 
Description: Transforms an HTML file into corresponding Haml code.
 
Options:
END
 
        opts.on('-r', '--rhtml', 'Parse RHTML tags.') do
          @module_opts[:rhtml] = true
        end
 
        super
      end
 
      def process_result
        super
 
        input = @options[:input]
        output = @options[:output]
 
        output.write(::Haml::HTML.new(input, @module_opts).render)
      end
    end
 
    # A class encapsulating executable functionality
    # specific to the css2sass executable.
    class CSS2Sass < Generic # :nodoc:
      def initialize(args)
        super
 
        require 'sass/css'
      end
 
      def set_opts(opts)
        opts.banner = <<END
Usage: css2sass [options] [INPUT] [OUTPUT]
 
Description: Transforms a CSS file into corresponding Sass code.
 
Options:
END
 
        super
      end
 
      def process_result
        super
 
        input = @options[:input]
        output = @options[:output]
 
        output.write(::Sass::CSS.new(input).render)
      end
    end
  end
end