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 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
+