lazibi 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,8 @@
1
+ #!/opt/local/bin/ruby
2
+
3
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'lazibi'
6
+
7
+ r = Lazibi.new
8
+ r.run
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
@@ -0,0 +1,2 @@
1
+ class abc
2
+ def
@@ -0,0 +1,10 @@
1
+ def a
2
+ # comment
3
+
4
+ def b
5
+
6
+ #comment
7
+ def c
8
+
9
+ def d
10
+ #
@@ -0,0 +1,3 @@
1
+ def abc
2
+
3
+ def def abc end
@@ -0,0 +1,7 @@
1
+ begin abc
2
+ rescue
3
+
4
+ begin def
5
+ #
6
+ rescue
7
+ #
@@ -0,0 +1,4 @@
1
+ Rails::Initializer.run do |config|
2
+ # See Rails::Configuration for more options
3
+
4
+ # Inflector.inflections do |inflect|
@@ -0,0 +1,2 @@
1
+ def
2
+ end
@@ -0,0 +1,4 @@
1
+ class abc
2
+ def a
3
+
4
+ def b
@@ -0,0 +1,2 @@
1
+ class basic
2
+ end
@@ -0,0 +1,4 @@
1
+ class abc
2
+ def
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ def a
2
+ # comment
3
+ end
4
+
5
+ def b
6
+ end
7
+
8
+ #comment
9
+ def c
10
+ end
11
+
12
+ def d
13
+ end
14
+ #
@@ -0,0 +1,3 @@
1
+ def abc end
2
+
3
+ def def abc end end
@@ -0,0 +1,9 @@
1
+ begin abc
2
+ rescue
3
+ end
4
+
5
+ begin def
6
+ #
7
+ rescue
8
+ end
9
+ #
@@ -0,0 +1,5 @@
1
+ Rails::Initializer.run do |config|
2
+ # See Rails::Configuration for more options
3
+ end
4
+
5
+ # Inflector.inflections do |inflect|
@@ -0,0 +1,3 @@
1
+ def
2
+ end
3
+ end
@@ -0,0 +1,7 @@
1
+ class abc
2
+ def a
3
+ end
4
+
5
+ def b
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+
4
+ require 'test/unit'
5
+ require 'lazibi'
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
+