lazibi 0.1.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.
- data/README +109 -0
- data/bin/lazibi +8 -0
- data/lib/lazibi.rb +273 -0
- data/test/fixtures/meta/basic_class.txt +1 -0
- data/test/fixtures/meta/class_with_def.txt +2 -0
- data/test/fixtures/meta/comment.txt +10 -0
- data/test/fixtures/meta/inline_end.txt +3 -0
- data/test/fixtures/meta/middle.txt +7 -0
- data/test/fixtures/meta/nested_comment.txt +4 -0
- data/test/fixtures/meta/partial_method.txt +2 -0
- data/test/fixtures/meta/two_methods.txt +4 -0
- data/test/fixtures/real/basic_class.txt +2 -0
- data/test/fixtures/real/class_with_def.txt +4 -0
- data/test/fixtures/real/comment.txt +14 -0
- data/test/fixtures/real/inline_end.txt +3 -0
- data/test/fixtures/real/middle.txt +9 -0
- data/test/fixtures/real/nested_comment.txt +5 -0
- data/test/fixtures/real/partial_method.txt +3 -0
- data/test/fixtures/real/two_methods.txt +7 -0
- data/test/test_helper.rb +5 -0
- data/test/test_unit.rb +96 -0
- metadata +69 -0
data/README
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
== Welcome to Lazibi
|
2
|
+
|
3
|
+
Lazibi is a meta language which allows you to use Python like syntax ( tab-indented block ) in
|
4
|
+
Ruby. It's backward compatible with plain Ruby if you indent your blocks properly.
|
5
|
+
|
6
|
+
The idea is to edit .py.rb files in a meta directory and let the engine generates .rb files in
|
7
|
+
the real directory for you.
|
8
|
+
|
9
|
+
== Examples
|
10
|
+
|
11
|
+
Is this Ruby or Python?
|
12
|
+
|
13
|
+
class MyClass
|
14
|
+
|
15
|
+
def hello
|
16
|
+
puts 'hello world'
|
17
|
+
|
18
|
+
MyClass.new.hello
|
19
|
+
|
20
|
+
More DIY Rails controller
|
21
|
+
|
22
|
+
class AuctionsController < ApplicationController
|
23
|
+
|
24
|
+
def index
|
25
|
+
@auctions = Auction.paginate :page => params[:page]
|
26
|
+
|
27
|
+
respond_to do |format|
|
28
|
+
format.html # index.rhtml
|
29
|
+
format.xml { render :xml => @auctions.to_xml }
|
30
|
+
|
31
|
+
|
32
|
+
Even sexier migrations ( with sexy_migration Rails plugin )
|
33
|
+
|
34
|
+
class CreateOrders < ActiveRecord::Migration
|
35
|
+
def self.up
|
36
|
+
create_table :orders do
|
37
|
+
fkey :user
|
38
|
+
fkey :auction
|
39
|
+
integer :bid_type
|
40
|
+
timestamps!
|
41
|
+
|
42
|
+
def self.down
|
43
|
+
drop_table :orders
|
44
|
+
|
45
|
+
== Download
|
46
|
+
|
47
|
+
gem install lazibi ( not yet available )
|
48
|
+
svn checkout http://lazibi.googlecode.com/svn/trunk/real lazibi
|
49
|
+
|
50
|
+
== Usage
|
51
|
+
|
52
|
+
Bootstrap
|
53
|
+
|
54
|
+
mkdir shiny_project
|
55
|
+
cd shiny_project
|
56
|
+
svn co $svn_path/shiny_project/trunk real # or hand create your project in the "real" folder
|
57
|
+
lazibi
|
58
|
+
|
59
|
+
Make sure everything still works
|
60
|
+
|
61
|
+
_start_a_new_terminal_
|
62
|
+
cd shiny_project/real
|
63
|
+
rake test / autotest
|
64
|
+
|
65
|
+
Start hacking ruby/python :/
|
66
|
+
|
67
|
+
cd shiny_project
|
68
|
+
$your_editor meta
|
69
|
+
|
70
|
+
== Tips
|
71
|
+
|
72
|
+
=== Rails fix
|
73
|
+
|
74
|
+
After bootstrap, edit config/boot.py.rb in meta
|
75
|
+
|
76
|
+
STDERR.puts %(Cannot find gem for Rails ~>#{version}.0:
|
77
|
+
Install the missing gem with 'gem install -v=#{version} rails', or
|
78
|
+
change environment.rb to define RAILS_GEM_VERSION with your desired version.
|
79
|
+
)
|
80
|
+
|
81
|
+
=== Manually create meta files
|
82
|
+
|
83
|
+
* Bootstrap your project as usual, just don't run lazibi
|
84
|
+
|
85
|
+
* setup environment
|
86
|
+
|
87
|
+
mkdir .backup
|
88
|
+
mkdir meta
|
89
|
+
|
90
|
+
* run lazibi
|
91
|
+
|
92
|
+
* create .py.rb files in corresponding directories inside 'meta', .rb files will be created and updated in 'real' as usual
|
93
|
+
|
94
|
+
|
95
|
+
== Known issues
|
96
|
+
|
97
|
+
Here document like long strings are likely to screw up code generation, try
|
98
|
+
to indent long strings like the fix for rails
|
99
|
+
|
100
|
+
== To Do
|
101
|
+
|
102
|
+
* Here doc fix
|
103
|
+
* Two way sync between real and meta
|
104
|
+
* Erb for rhtml
|
105
|
+
|
106
|
+
== Author
|
107
|
+
* Jinjing (mailto:nfjinjing@gmail.com)
|
108
|
+
|
109
|
+
Released under the MIT license (included)
|
data/bin/lazibi
ADDED
data/lib/lazibi.rb
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'find'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class Lazibi
|
6
|
+
attr :config
|
7
|
+
|
8
|
+
def load_config
|
9
|
+
@config = {}
|
10
|
+
default = {:exclude => ['^vendor']}
|
11
|
+
if File.exists? '.lazibi'
|
12
|
+
f = open '.lazibi'
|
13
|
+
h = YAML.load(f)
|
14
|
+
for k in h.keys
|
15
|
+
begin
|
16
|
+
@config[k.to_sym] = h[k]
|
17
|
+
rescue
|
18
|
+
raise "wrong pattern #{h[k]}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@config = default
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def init_meta
|
27
|
+
# backup real
|
28
|
+
real_dir = 'real'
|
29
|
+
if File.directory? real_dir
|
30
|
+
backup_dir = '.backup'
|
31
|
+
unless File.exists? backup_dir
|
32
|
+
FileUtils.cp_r real_dir, backup_dir
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise 'No directory named "real"'
|
36
|
+
end
|
37
|
+
|
38
|
+
# generate meta
|
39
|
+
meta_dir = 'meta'
|
40
|
+
if File.exists? meta_dir
|
41
|
+
if File.directory? meta_dir
|
42
|
+
FileUtils.rm_rf meta_dir
|
43
|
+
else
|
44
|
+
raise 'meta directory is reserved for instiki'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
puts "Generating meta files:"
|
50
|
+
puts "-" * 40
|
51
|
+
Dir.glob(File.join('real', '**', '*.rb')) do |f|
|
52
|
+
if skip_path? f
|
53
|
+
puts "- #{f}"
|
54
|
+
next
|
55
|
+
end
|
56
|
+
|
57
|
+
next unless File.file? f
|
58
|
+
next if f =~ /.*[.]py[.]rb$/
|
59
|
+
py_path = convert_path f
|
60
|
+
dir_name = File.dirname py_path
|
61
|
+
|
62
|
+
puts ' ' + py_path
|
63
|
+
FileUtils.mkdir_p dir_name
|
64
|
+
make_py f, py_path
|
65
|
+
end
|
66
|
+
|
67
|
+
puts "-" * 40
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def skip_path?(path)
|
72
|
+
return false if @config[:exclude].nil?
|
73
|
+
@config[:exclude].each do |f|
|
74
|
+
offset = 'meta'.size + 1
|
75
|
+
return true if path[offset..-1] =~ Regexp.new(f)
|
76
|
+
end
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
80
|
+
def convert_path( path )
|
81
|
+
if path =~ /.*[.]py[.]rb/
|
82
|
+
from = 'meta'
|
83
|
+
to = 'real'
|
84
|
+
old_ext = '.py.rb'
|
85
|
+
new_ext = '.rb'
|
86
|
+
else
|
87
|
+
from = 'real'
|
88
|
+
to = 'meta'
|
89
|
+
old_ext = '.rb'
|
90
|
+
new_ext = '.py.rb'
|
91
|
+
end
|
92
|
+
|
93
|
+
dir_name = File.dirname path
|
94
|
+
base_name = File.basename path, old_ext
|
95
|
+
|
96
|
+
new_dir_name = to + dir_name[from.size..-1]
|
97
|
+
new_path = File.join new_dir_name, base_name + new_ext
|
98
|
+
end
|
99
|
+
|
100
|
+
def make_py( rb_path, py_path )
|
101
|
+
rb = open(rb_path).read
|
102
|
+
|
103
|
+
py_file = open(py_path, 'w')
|
104
|
+
py_file.write(to_py(rb))
|
105
|
+
py_file.close
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_py( rb )
|
109
|
+
py = []
|
110
|
+
rb.split("\n").each do |l|
|
111
|
+
if l.strip =~ /^end$/
|
112
|
+
next
|
113
|
+
end
|
114
|
+
s = l
|
115
|
+
if l.rstrip[-3..-1] == 'end'
|
116
|
+
s = l.rstrip[0...-3].rstrip
|
117
|
+
end
|
118
|
+
|
119
|
+
py << s
|
120
|
+
end
|
121
|
+
|
122
|
+
py.join("\n")
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def run
|
127
|
+
load_config
|
128
|
+
init_meta unless File.exists? '.backup'
|
129
|
+
@metas = {}
|
130
|
+
while true
|
131
|
+
current_metas = get_metas
|
132
|
+
current_metas.each_pair do |meta, m_time|
|
133
|
+
if @metas[meta] != m_time
|
134
|
+
update_rb meta
|
135
|
+
puts "+ #{meta}..."
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@metas = current_metas
|
139
|
+
sleep 1
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_metas
|
144
|
+
meta_files = File.join('meta', "**", "*.py.rb")
|
145
|
+
metas = {}
|
146
|
+
Dir.glob(meta_files).each do |t|
|
147
|
+
metas[t] = File.mtime t
|
148
|
+
end
|
149
|
+
metas
|
150
|
+
end
|
151
|
+
|
152
|
+
def update_rb( meta_name )
|
153
|
+
meta = open(meta_name)
|
154
|
+
real_name = convert_path meta_name
|
155
|
+
begin
|
156
|
+
real_rb = open( real_name, 'w' )
|
157
|
+
real_rb.write(to_rb(meta.read))
|
158
|
+
rescue Exception => e
|
159
|
+
puts e
|
160
|
+
ensure
|
161
|
+
real_rb.close unless real_rb.nil?
|
162
|
+
end
|
163
|
+
meta.close
|
164
|
+
end
|
165
|
+
|
166
|
+
def to_rb( content )
|
167
|
+
insert_end content
|
168
|
+
end
|
169
|
+
|
170
|
+
def insert_end( content )
|
171
|
+
@lines = content.split("\n")
|
172
|
+
progress = 0
|
173
|
+
while progress < @lines.size
|
174
|
+
lines = @lines[progress..-1]
|
175
|
+
lines.each_index do |index|
|
176
|
+
l = lines[index]
|
177
|
+
if start_anchor?(get_rest(l))
|
178
|
+
relative_index_for_end = find_end( lines[index..-1], get_indent(l))
|
179
|
+
unless relative_index_for_end
|
180
|
+
progress += 1
|
181
|
+
break
|
182
|
+
end
|
183
|
+
index_for_end = relative_index_for_end + index
|
184
|
+
lines[index_for_end] = lines[index_for_end] + "\n" + ' ' * get_indent(l) + "end"
|
185
|
+
head = @lines[0...progress]
|
186
|
+
tail = lines[index..-1].join("\n").split("\n")
|
187
|
+
@lines = head + tail
|
188
|
+
progress += 1
|
189
|
+
break
|
190
|
+
end
|
191
|
+
progress += 1
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
result = @lines.join("\n")
|
196
|
+
end
|
197
|
+
|
198
|
+
def find_end( lines, indent )
|
199
|
+
return 0 if lines.size == 1
|
200
|
+
|
201
|
+
anchor = 0
|
202
|
+
|
203
|
+
lines = lines[1..-1]
|
204
|
+
lines.each_index do |i|
|
205
|
+
l = lines[i]
|
206
|
+
next if l.strip == ''
|
207
|
+
if l.strip =~ /^#/
|
208
|
+
if get_indent(l) > indent
|
209
|
+
anchor = i + 1
|
210
|
+
end
|
211
|
+
next
|
212
|
+
end
|
213
|
+
return anchor if get_indent(l) < indent
|
214
|
+
if get_indent(l) == indent
|
215
|
+
rest = get_rest l
|
216
|
+
if middle_anchor? rest
|
217
|
+
anchor = i + 1
|
218
|
+
next
|
219
|
+
elsif end_anchor? rest
|
220
|
+
return false
|
221
|
+
else
|
222
|
+
return anchor
|
223
|
+
end
|
224
|
+
end
|
225
|
+
anchor = i + 1
|
226
|
+
end
|
227
|
+
return anchor
|
228
|
+
end
|
229
|
+
|
230
|
+
def get_indent( line )
|
231
|
+
line =~ /( *)/
|
232
|
+
$1.size
|
233
|
+
end
|
234
|
+
|
235
|
+
def get_rest( line )
|
236
|
+
line =~/( *)/
|
237
|
+
$'
|
238
|
+
end
|
239
|
+
|
240
|
+
def begin_keys
|
241
|
+
s = %w( module def class if begin for while unless do )
|
242
|
+
m = ['\sdo\s*$|\sdo\s+(\|[^|]+\|)']
|
243
|
+
s.map!{|key| "^#{key}\\b"}
|
244
|
+
|
245
|
+
Regexp.new(s.concat(m).join('|'))
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
|
250
|
+
def middle_keys
|
251
|
+
s = %w( rescue else ensure elsif )
|
252
|
+
s.map!{|key| "^#{key}\\b"}
|
253
|
+
Regexp.new(s.join('|'))
|
254
|
+
end
|
255
|
+
|
256
|
+
def end_keys
|
257
|
+
/^end\b/
|
258
|
+
end
|
259
|
+
|
260
|
+
def start_anchor?( str )
|
261
|
+
str.gsub! /"[^"]+"|'[^']+'/, ''
|
262
|
+
return false if str =~ /^#/
|
263
|
+
return true if str =~ begin_keys
|
264
|
+
end
|
265
|
+
|
266
|
+
def middle_anchor?( str )
|
267
|
+
str =~ middle_keys
|
268
|
+
end
|
269
|
+
|
270
|
+
def end_anchor?(str)
|
271
|
+
str =~ end_keys
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class basic
|
data/test/test_helper.rb
ADDED
data/test/test_unit.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
class TestLazibi < Test::Unit::TestCase
|
5
|
+
attr :fixtures, :expected
|
6
|
+
|
7
|
+
def setup
|
8
|
+
|
9
|
+
# load fixtures
|
10
|
+
@meta = {}
|
11
|
+
@real = {}
|
12
|
+
|
13
|
+
fixture_dir = File.dirname(__FILE__) + '/fixtures/meta'
|
14
|
+
|
15
|
+
Dir.open(fixture_dir).each do |fn|
|
16
|
+
next unless fn =~ /[.]txt$/
|
17
|
+
@meta[fn.scan(/(.*)[.]/).to_s.to_sym] = File.read(fixture_dir + "/#{fn}")
|
18
|
+
end
|
19
|
+
|
20
|
+
expected_dir = File.dirname(__FILE__) + '/fixtures/real'
|
21
|
+
Dir.open(expected_dir).each do |fn|
|
22
|
+
next unless fn =~ /[.]txt$/
|
23
|
+
@real[fn.scan(/(.*)[.]/).to_s.to_sym] = File.read(expected_dir + "/#{fn}")
|
24
|
+
end
|
25
|
+
|
26
|
+
@r = Lazibi.new
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def test_start_anchor?
|
31
|
+
assert @r.start_anchor?( 'class' )
|
32
|
+
assert @r.start_anchor?( 'do |abc| ')
|
33
|
+
assert @r.start_anchor?( 'do |abc,def| ')
|
34
|
+
assert !@r.start_anchor?( '"abc do "')
|
35
|
+
assert !@r.start_anchor?( '"abc do |"')
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_middle_anchor?
|
39
|
+
assert !@r.middle_anchor?( '' )
|
40
|
+
assert @r.middle_anchor?( 'rescue' )
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_find_end
|
44
|
+
assert_find :basic_class, 0, 0
|
45
|
+
assert_find :class_with_def, 0, 1
|
46
|
+
assert_find :class_with_def, 0, 1
|
47
|
+
assert @r.find_end(@meta[:class_with_def].split("\n")[1..-1], 2 ) == 0
|
48
|
+
assert_find :two_methods, 0, 3
|
49
|
+
assert @r.find_end(@meta[:two_methods].split("\n")[1..-1], 2) == 0
|
50
|
+
assert_find :partial_method, 2, 0
|
51
|
+
assert_find :middle, 0, 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_convert_path
|
55
|
+
assert @r.convert_path( 'meta/abc.py.rb' ) == 'real/abc.rb', @r.convert_path('meta/abc.rb')
|
56
|
+
assert @r.convert_path( 'real/abc.rb' ) == 'meta/abc.py.rb'
|
57
|
+
assert @r.convert_path( 'meta/lib/abc.py.rb' ) == 'real/lib/abc.rb'
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_convert_content
|
61
|
+
@meta.keys.reject{|k| ['partial_method', 'inline_end'].include? k.to_s }.each do |k|
|
62
|
+
assert_convert k
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_to_rb
|
67
|
+
assert_to_rb :partial_method
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_to_py
|
71
|
+
assert_to_py :inline_end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
private
|
76
|
+
def assert_find( name, indent, end_i )
|
77
|
+
assert_equal @r.find_end(@meta[name].split("\n"), indent), end_i
|
78
|
+
end
|
79
|
+
|
80
|
+
def assert_to_rb( name )
|
81
|
+
assert_equal @r.to_rb( @meta[name]), @real[name], name
|
82
|
+
end
|
83
|
+
|
84
|
+
def assert_to_py( name )
|
85
|
+
assert_equal @r.to_py( @real[name]), @meta[name], name
|
86
|
+
end
|
87
|
+
|
88
|
+
def assert_convert( name )
|
89
|
+
assert_to_rb(name)
|
90
|
+
assert_to_py(name)
|
91
|
+
end
|
92
|
+
|
93
|
+
def assert_identity( s )
|
94
|
+
assert_equal @r.to_rb( @r.to_py( s ) ), s
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.3
|
3
|
+
specification_version: 1
|
4
|
+
name: lazibi
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.1
|
7
|
+
date: 2007-06-13 00:00:00 +08:00
|
8
|
+
summary: Python like syntax for Ruby
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: nfjinjing@gmail.com
|
12
|
+
homepage: ""
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: lazibi
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Jinjing
|
31
|
+
files:
|
32
|
+
- bin/lazibi
|
33
|
+
- test/fixtures
|
34
|
+
- test/test_helper.rb
|
35
|
+
- test/test_unit.rb
|
36
|
+
- test/fixtures/meta
|
37
|
+
- test/fixtures/real
|
38
|
+
- test/fixtures/meta/basic_class.txt
|
39
|
+
- test/fixtures/meta/class_with_def.txt
|
40
|
+
- test/fixtures/meta/comment.txt
|
41
|
+
- test/fixtures/meta/inline_end.txt
|
42
|
+
- test/fixtures/meta/middle.txt
|
43
|
+
- test/fixtures/meta/nested_comment.txt
|
44
|
+
- test/fixtures/meta/partial_method.txt
|
45
|
+
- test/fixtures/meta/two_methods.txt
|
46
|
+
- test/fixtures/real/basic_class.txt
|
47
|
+
- test/fixtures/real/class_with_def.txt
|
48
|
+
- test/fixtures/real/comment.txt
|
49
|
+
- test/fixtures/real/inline_end.txt
|
50
|
+
- test/fixtures/real/middle.txt
|
51
|
+
- test/fixtures/real/nested_comment.txt
|
52
|
+
- test/fixtures/real/partial_method.txt
|
53
|
+
- test/fixtures/real/two_methods.txt
|
54
|
+
- lib/lazibi.rb
|
55
|
+
- README
|
56
|
+
test_files:
|
57
|
+
- test/test_unit.rb
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
extra_rdoc_files:
|
61
|
+
- README
|
62
|
+
executables:
|
63
|
+
- lazibi
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
dependencies: []
|
69
|
+
|