pprb 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Zahary Karadjov, Stefan Dragnev
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require './lib/pprb'
4
+
5
+ begin
6
+ require 'jeweler'
7
+
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "pprb"
10
+ gem.authors = ["Zahary Karadjov", "Stefan Dragnev"]
11
+ gem.summary = "PPRB The little preprocessor that could"
12
+ gem.description = "PPRB is a code preprocessor and text templating engine with minimalistic syntax and strong emphasis on eliminating any code duplication in template files"
13
+ gem.email = "zahary@gmail.com"
14
+ gem.homepage = "http://github.com/zah/pprb"
15
+ gem.version = PPRB::Version::STRING
16
+
17
+ gem.executable = 'pprb'
18
+
19
+ gem.files.exclude 'CMake'
20
+ gem.files.exclude 'VisualStudio'
21
+
22
+ gem.add_development_dependency "thoughtbot-shoulda"
23
+ gem.add_dependency "trollop"
24
+ end
25
+
26
+ #Jeweler::GemcutterTasks.new
27
+ rescue LoadError
28
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
29
+ end
30
+
31
+ require 'rake/testtask'
32
+ Rake::TestTask.new(:test) do |test|
33
+ test.libs << 'lib' << 'test'
34
+ test.pattern = 'test/**/*_test.rb'
35
+ test.verbose = true
36
+ end
37
+
38
+ begin
39
+ require 'rcov/rcovtask'
40
+ Rcov::RcovTask.new do |test|
41
+ test.libs << 'test'
42
+ test.pattern = 'test/**/*_test.rb'
43
+ test.verbose = true
44
+ end
45
+ rescue LoadError
46
+ task :rcov do
47
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
48
+ end
49
+ end
50
+
51
+ task :test => :check_dependencies
52
+
53
+ task :default => :test
54
+
55
+ require 'rake/rdoctask'
56
+ Rake::RDocTask.new do |rdoc|
57
+ if File.exist?('VERSION')
58
+ version = File.read('VERSION')
59
+ else
60
+ version = ""
61
+ end
62
+
63
+ rdoc.rdoc_dir = 'rdoc'
64
+ rdoc.title = "pprb #{version}"
65
+ rdoc.rdoc_files.include('README*')
66
+ rdoc.rdoc_files.include('lib/**/*.rb')
67
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../lib"
4
+
5
+ require 'rubygems'
6
+ require 'pprb'
7
+ require 'trollop'
8
+
9
+ options = Trollop::options do
10
+ banner "PPRB #{PPRB::Version::STRING} usage: pprb source [options]"
11
+ opt :out, "Output file. Unless supplied prints to STDOUT", :short => 'o', :type => String
12
+ end
13
+
14
+ source = ARGV.shift
15
+
16
+ Trollop::die "Please, provide a source file" unless source
17
+
18
+ open(source, "r") do |input|
19
+ target_output = PPRB::render input
20
+
21
+ unless options.out
22
+ puts target_output
23
+ else
24
+ open(opts[:out], 'w').write target_output
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ > hw = "Hello World"
2
+
3
+ % rb
4
+ puts "Arbitrary ruby code is executed here"
5
+ puts "Functions could be defined"
6
+
7
+ def test a, b
8
+ a + b
9
+ end
10
+ -
11
+
12
+ > # this defines a function, but keeps the standard mode for
13
+ > # "lines without special symbols are output"
14
+ % def hello_world_template
15
+ puts("Hello World")
16
+ % 3.times
17
+ puts("Hello Loop")
18
+ -
19
+ -
20
+
21
+ void main()
22
+ {
23
+ > hello_world_template
24
+
25
+ % 6.times
26
+ printf("%d", `test 5, 10`);
27
+ -
28
+ }
29
+
@@ -0,0 +1,235 @@
1
+ module PPRB
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 9
5
+ PATCH = 0
6
+
7
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
+ end
9
+
10
+ def self.render source
11
+ PPRB.new(source).run
12
+ end
13
+
14
+ def self.compile source
15
+ PPRB.new(source)
16
+ end
17
+
18
+ class PPRB
19
+ # source is either a File object or a string
20
+ # start_state is either :pp or :rb
21
+ def initialize source, start_state = :pp
22
+ @source = source
23
+ @path = File.expand_path(source.path) if source.class == File
24
+
25
+ @BLOCK = @LINE = @END = @TICKS = ''
26
+ profile :default
27
+
28
+ @ruby_output = ''
29
+ @target_output = ''
30
+
31
+ @input_state = [start_state]
32
+ @last_emitted = :code
33
+
34
+ load_rules
35
+ source.lines.each { |l| process_line l }
36
+ @ruby_output << ']' if @last_emitted == :text
37
+ end
38
+
39
+ def run
40
+ run_and_translate_errors @ruby_output
41
+ @target_output
42
+ end
43
+
44
+ attr_reader :ruby_output, :target_output
45
+
46
+ PROFILES = {
47
+ :default => {
48
+ :block => /^%(.*)/,
49
+ :line => /^>(.*)/,
50
+ :end => /^-$/,
51
+ :ticks => /`(.*?)`/
52
+ },
53
+
54
+ :c_parsable => {
55
+ :block => %r[^//\s*%(.*)],
56
+ :line => %r[^//\s*>(.*)],
57
+ :end => %r[^//\s*-$],
58
+ :ticks => /\brb_(\w+?)_\b/
59
+ },
60
+ }
61
+
62
+ def profile filter = nil, prof = nil, overlay = nil
63
+ # sort-out the passed arguments
64
+ overlay = filter if filter.class == Hash
65
+ overlay = prof if prof.class == Hash
66
+ prof = filter if filter.class == Symbol
67
+ filter = nil if filter != nil and filter.class != String
68
+ prof = nil if prof != nil and prof.class != Symbol
69
+
70
+ raise "No profile or overlay specified" if overlay == nil and prof == nil
71
+
72
+ unless filter
73
+ if prof
74
+ profile = PROFILES[prof]
75
+ raise "Unknown profile: #{p}" if profile == nil
76
+ config profile
77
+ end
78
+
79
+ config overlay if overlay
80
+ else
81
+ profile nil, prof, overlay if File.fnmatch(filter, @path)
82
+ end
83
+ end
84
+
85
+ def config options
86
+ for key, value in options
87
+ var = "@#{key.to_s.upcase}"
88
+ raise "Unknown option: #{key}" if instance_variable_get(var) == nil
89
+ instance_variable_set var, value
90
+ end
91
+ end
92
+
93
+ private
94
+ def process_line line
95
+ case line.strip
96
+ when @BLOCK then begin_block $1+"\n"
97
+ when @END then end_block
98
+ when @LINE then emit $1+"\n", antistate(@input_state.last)
99
+ else emit line, @input_state.last
100
+ end
101
+ end
102
+
103
+ def end_block
104
+ raise "Unexpected block end (no matching block start)." if @input_state.size == 1
105
+
106
+ if @input_state.pop == :pp
107
+ emit "end\n", :rb
108
+ else
109
+ emit '', :pp
110
+ end
111
+ end
112
+
113
+ def begin_block line
114
+ if @input_state.last == :pp
115
+ case line
116
+ when /^\s*rb/ then
117
+ @input_state.push :rb
118
+ emit '', :pp
119
+ when /\bdef|\bfor\b|\bwhile\b|\buntil\b|\bdo\b|\bif\b|\bunless\b|\case\b|\bclass\b|\bmodule\b|\bbegin\b/ then
120
+ @input_state.push :pp
121
+ emit line, :rb
122
+ else
123
+ @input_state.push :pp
124
+ emit line.rstrip + " do\n", :rb
125
+ end
126
+ else # state :rb
127
+ @input_state.push :pp
128
+ emit "begin ", :rb
129
+ emit line, :pp
130
+ end
131
+ end
132
+
133
+ def emit line, state
134
+ if state == :rb
135
+ if @last_emitted == :text
136
+ @ruby_output << "]; #{line}"
137
+ @last_emitted = :code
138
+ else
139
+ @ruby_output << line
140
+ end
141
+ else # state :pp
142
+ if @last_emitted == :code
143
+ @ruby_output << "target_out %[#{escape_code line}"
144
+ @last_emitted = :text
145
+ else
146
+ @ruby_output << escape_code(line)
147
+ end
148
+ end
149
+ end
150
+
151
+ def antistate state
152
+ (state == :pp) ? (:rb) : (:pp)
153
+ end
154
+
155
+ def escape_code str
156
+ ruby_snippets = []
157
+ # we don't want anything escaped withing ruby snippets, so first we move them out
158
+ str.gsub!(@TICKS) { ruby_snippets << $1; "%%#{ruby_snippets.size - 1}" }
159
+ # after escaping what's necessary, we move them back in
160
+ str.gsub('\\', '\\\\\\').gsub(']', '\\]').gsub('[', '\\[').gsub(/%%(\d+)/) { "\#{#{ruby_snippets[ $1.to_i ]}}" }
161
+ end
162
+
163
+ def pprb_include_dirs
164
+ return @pprb_include_dirs if @pprb_include_dirs != nil
165
+ return [] if @path == nil
166
+
167
+ dir = File.dirname @path
168
+ dirs = []
169
+
170
+ while true
171
+ dirs << dir
172
+
173
+ modules_dir = dir + "/pprb_modules"
174
+ dirs << modules_dir if File.directory? modules_dir
175
+
176
+ break if dir == '/' or dir == '/cygdrive'
177
+
178
+ parent_dir = File.dirname dir
179
+ break if parent_dir == dir # this a terminating condition on Windows
180
+
181
+ dir = parent_dir
182
+ end
183
+
184
+ @pprb_include_dirs = dirs.reverse
185
+ end
186
+
187
+ def load_rules
188
+ pprb_include_dirs.each do |dir|
189
+ next unless File.exist?(rules = "#{dir}/pprb.rules")
190
+ open(rules) { |f| run_and_translate_errors(f.read, rules) }
191
+ end
192
+ end
193
+
194
+ def use file
195
+ found = false
196
+
197
+ pprb_include_dirs.each do |dir|
198
+ next unless File.exist?(include = "#{dir}/#{file}.pprb.i")
199
+ found = true
200
+ open(include) do |file|
201
+ pprb = PPRB.new(file.read, :rb)
202
+ run_and_translate_errors pprb.ruby_output, include
203
+ end
204
+ end
205
+
206
+ raise "Could not find PPRB module '#{file}'" unless found
207
+ end
208
+
209
+ def target_out text
210
+ @target_output << text
211
+ end
212
+
213
+ def run_and_translate_errors code, filename = @path
214
+ instance_eval code
215
+ rescue RuntimeError, Exception => err
216
+ source_line = nil
217
+ p err
218
+ err.backtrace.grep(/\(eval\):(\d+)/) { source_line ||= $1.to_i }
219
+
220
+ if source_line
221
+ $stderr.puts "#{filename}:#{source_line}: error: #{err.to_s}"
222
+ $stderr.puts
223
+
224
+ $stderr.puts "Ruby backtrace:"
225
+ $stderr.puts err.backtrace
226
+
227
+ $stderr.puts "Working directory: #{Dir.pwd}"
228
+ else
229
+ raise err
230
+ end
231
+ end
232
+ end
233
+
234
+ end
235
+
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class PprbTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'pprb'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pprb
3
+ version: !ruby/object:Gem::Version
4
+ hash: 59
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 0
10
+ version: 0.9.0
11
+ platform: ruby
12
+ authors:
13
+ - Zahary Karadjov
14
+ - Stefan Dragnev
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-04-14 00:00:00 +03:00
20
+ default_executable: pprb
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: thoughtbot-shoulda
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: trollop
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ description: PPRB is a code preprocessor and text templating engine with minimalistic syntax and strong emphasis on eliminating any code duplication in template files
51
+ email: zahary@gmail.com
52
+ executables:
53
+ - pprb
54
+ extensions: []
55
+
56
+ extra_rdoc_files:
57
+ - LICENSE
58
+ files:
59
+ - .document
60
+ - LICENSE
61
+ - Rakefile
62
+ - bin/pprb
63
+ - examples/hw.c
64
+ - lib/pprb.rb
65
+ - test/pprb_test.rb
66
+ - test/test_helper.rb
67
+ has_rdoc: true
68
+ homepage: http://github.com/zah/pprb
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.5.0
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: PPRB The little preprocessor that could
101
+ test_files:
102
+ - test/pprb_test.rb
103
+ - test/test_helper.rb