duby 0.0.2-java → 0.0.3-java
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/README.txt +18 -7
- data/Rakefile +72 -0
- data/examples/ant/example-build.xml +7 -0
- data/examples/appengine/Rakefile +8 -67
- data/examples/appengine/Readme +4 -3
- data/examples/appengine/lib/duby/appengine_tasks.rb +173 -0
- data/examples/appengine/lib/duby/plugin/datastore.rb +92 -31
- data/examples/appengine/lib/duby_task.rb +61 -0
- data/examples/appengine/src/com/ribrdb/DubyApp.duby +32 -6
- data/examples/appengine/src/com/ribrdb/list.dhtml +2 -2
- data/examples/appengine/{config.ru → src/config.ru} +0 -0
- data/examples/bintrees.duby +66 -0
- data/examples/dynamic.duby +17 -0
- data/examples/fib.duby +3 -11
- data/examples/fields.duby +3 -3
- data/examples/fractal.duby +1 -3
- data/examples/sort_closure.duby +7 -0
- data/examples/swing.duby +11 -11
- data/javalib/duby-bootstrap.jar +0 -0
- data/javalib/dynalang-invoke-0.1.jar +0 -0
- data/lib/duby.rb +168 -35
- data/lib/duby/ast.rb +224 -27
- data/lib/duby/ast/call.rb +85 -25
- data/lib/duby/ast/class.rb +112 -28
- data/lib/duby/ast/flow.rb +65 -44
- data/lib/duby/ast/intrinsics.rb +223 -21
- data/lib/duby/ast/literal.rb +67 -16
- data/lib/duby/ast/local.rb +36 -40
- data/lib/duby/ast/method.rb +83 -67
- data/lib/duby/ast/structure.rb +105 -23
- data/lib/duby/compiler.rb +83 -28
- data/lib/duby/env.rb +33 -0
- data/lib/duby/jvm/base.rb +210 -0
- data/lib/duby/jvm/compiler.rb +293 -219
- data/lib/duby/jvm/method_lookup.rb +77 -67
- data/lib/duby/jvm/source_compiler.rb +250 -157
- data/lib/duby/jvm/source_generator/builder.rb +53 -49
- data/lib/duby/jvm/source_generator/loops.rb +9 -9
- data/lib/duby/jvm/source_generator/precompile.rb +35 -25
- data/lib/duby/jvm/typer.rb +19 -10
- data/lib/duby/jvm/types.rb +127 -68
- data/lib/duby/jvm/types/basic_types.rb +26 -13
- data/lib/duby/jvm/types/enumerable.rb +6 -4
- data/lib/duby/jvm/types/factory.rb +49 -13
- data/lib/duby/jvm/types/floats.rb +16 -0
- data/lib/duby/jvm/types/integers.rb +63 -2
- data/lib/duby/jvm/types/intrinsics.rb +43 -21
- data/lib/duby/jvm/types/methods.rb +326 -86
- data/lib/duby/jvm/types/number.rb +3 -0
- data/lib/duby/nbcompiler.rb +1 -1
- data/lib/duby/plugin/edb.rb +1 -1
- data/lib/duby/plugin/java.rb +10 -1
- data/lib/duby/transform.rb +134 -46
- data/lib/duby/typer.rb +75 -50
- data/test/test_ast.rb +106 -106
- data/test/test_compilation.rb +46 -32
- data/test/test_env.rb +42 -0
- data/test/test_java_typer.rb +35 -51
- data/test/test_javac_compiler.rb +4 -1
- data/test/test_jvm_compiler.rb +564 -133
- data/test/test_typer.rb +68 -92
- metadata +37 -21
- data/examples/README +0 -16
- data/lib/duby/c/compiler.rb +0 -134
- data/lib/duby/old/compiler_old.rb +0 -845
- data/lib/duby/old/declaration.rb +0 -72
- data/lib/duby/old/mapper.rb +0 -72
- data/lib/duby/old/signature.rb +0 -52
- data/lib/duby/old/typer_old.rb +0 -163
- data/lib/duby/plugin/math.rb +0 -84
- data/test/test_math_plugin.rb +0 -87
data/History.txt
CHANGED
data/README.txt
CHANGED
@@ -20,20 +20,31 @@ output either JVM bytecode or Java source files.
|
|
20
20
|
duby <script.duby>
|
21
21
|
duby -e "inline script"
|
22
22
|
dubyc <script.duby>
|
23
|
-
dubyc -e "inline script" # produces
|
23
|
+
dubyc -e "inline script" # produces DashE.class
|
24
24
|
dubyc -java <script.duby>
|
25
|
-
dubyc -java -e "inline script" # produces
|
25
|
+
dubyc -java -e "inline script" # produces DashE.java
|
26
26
|
|
27
27
|
== REQUIREMENTS:
|
28
28
|
|
29
|
-
* JRuby 1.
|
29
|
+
* JRuby 1.5.0 or higher.
|
30
30
|
* BiteScript 0.0.5 or higher
|
31
31
|
|
32
32
|
== INSTALL:
|
33
33
|
|
34
|
+
If your "gem" command is the one from JRuby:
|
35
|
+
|
34
36
|
* gem install duby
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
jruby
|
39
|
-
|
38
|
+
Otherwise:
|
39
|
+
|
40
|
+
* jruby -S gem install duby
|
41
|
+
|
42
|
+
Only JRuby is supported at this time.
|
43
|
+
|
44
|
+
== For Java tools:
|
45
|
+
|
46
|
+
To build the Duby jars from source you should have a checkout of both jruby and
|
47
|
+
bitescript in Duby's parent directory. Run "ant jar-complete" in jruby, then in
|
48
|
+
the duby directory "../jruby/bin/jruby -S rake jar" to build the Duby jar. Use
|
49
|
+
"jar:complete" instead to produce a free-standing jar file with JRuby and the
|
50
|
+
JRubyParser libraries included.
|
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'java'
|
4
|
+
$: << './lib'
|
5
|
+
require 'duby'
|
6
|
+
require 'jruby/compiler'
|
7
|
+
require 'ant'
|
4
8
|
|
5
9
|
task :default => :test
|
6
10
|
|
@@ -11,3 +15,71 @@ Rake::TestTask.new :test do |t|
|
|
11
15
|
t.test_files = FileList["test/**/*.rb"]
|
12
16
|
java.lang.System.set_property("jruby.duby.enabled", "true")
|
13
17
|
end
|
18
|
+
|
19
|
+
task :init do
|
20
|
+
mkdir_p 'dist'
|
21
|
+
mkdir_p 'build'
|
22
|
+
end
|
23
|
+
|
24
|
+
task :clean do
|
25
|
+
ant.delete :quiet => true, :dir => 'build'
|
26
|
+
ant.delete :quiet => true, :dir => 'dist'
|
27
|
+
end
|
28
|
+
|
29
|
+
task :compile => :init do
|
30
|
+
# build the Ruby sources
|
31
|
+
puts "Compiling Ruby sources"
|
32
|
+
JRuby::Compiler.compile_argv([
|
33
|
+
'-t', 'build',
|
34
|
+
'--javac',
|
35
|
+
'src/org/jruby/duby/duby_command.rb'
|
36
|
+
])
|
37
|
+
|
38
|
+
# build the Duby sources
|
39
|
+
puts "Compiling Duby sources"
|
40
|
+
Dir.chdir 'src' do
|
41
|
+
classpath = Duby::Env.encode_paths([
|
42
|
+
'javalib/jruby-complete.jar',
|
43
|
+
'javalib/JRubyParser.jar',
|
44
|
+
'dist/duby.jar',
|
45
|
+
'build',
|
46
|
+
'/usr/share/ant/lib/ant.jar'
|
47
|
+
])
|
48
|
+
Duby.compile(
|
49
|
+
'-c', classpath,
|
50
|
+
'-d', '../build',
|
51
|
+
'org/jruby/duby',
|
52
|
+
'duby/lang')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
task :jar => :compile do
|
57
|
+
ant.jar :jarfile => 'dist/duby.jar' do
|
58
|
+
fileset :dir => 'lib'
|
59
|
+
fileset :dir => 'build'
|
60
|
+
fileset :dir => '.', :includes => 'bin/*'
|
61
|
+
fileset :dir => '../bitescript/lib'
|
62
|
+
manifest do
|
63
|
+
attribute :name => 'Main-Class', :value => 'org.jruby.duby.DubyCommand'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
namespace :jar do
|
69
|
+
task :complete => :jar do
|
70
|
+
ant.jar :jarfile => 'dist/duby-complete.jar' do
|
71
|
+
zipfileset :src => 'dist/duby.jar'
|
72
|
+
zipfileset :src => 'javalib/jruby-complete.jar'
|
73
|
+
zipfileset :src => 'javalib/JRubyParser.jar'
|
74
|
+
manifest do
|
75
|
+
attribute :name => 'Main-Class', :value => 'org.jruby.duby.DubyCommand'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
task :bootstrap => :compile do
|
81
|
+
ant.jar :jarfile => 'javalib/duby-bootstrap.jar' do
|
82
|
+
fileset :dir => 'build'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/examples/appengine/Rakefile
CHANGED
@@ -1,72 +1,13 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
require 'appengine-tools/xml-formatter'
|
1
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/lib')
|
2
|
+
require 'duby/appengine_tasks'
|
4
3
|
|
5
|
-
|
6
|
-
LIB = File.expand_path(File.dirname(__FILE__) + '/lib')
|
7
|
-
WAR = File.expand_path(File.dirname(__FILE__) + '/war')
|
8
|
-
CONFIG_RU = File.expand_path(File.dirname(__FILE__) + '/config.ru')
|
9
|
-
SERVLET = AppEngine::SDK::SDK_ROOT +
|
10
|
-
'/lib/shared/geronimo-servlet_2.5_spec-1.2.jar'
|
11
|
-
APIS = AppEngine::SDK::API_JAR
|
4
|
+
appengine_app :app
|
12
5
|
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
DUBY_APP = "#{Duby.dest_path}/com/ribrdb/DubyApp.class"
|
7
|
+
MODEL = "#{Duby.dest_path}/com/google/appengine/ext/duby/db/Model.class"
|
8
|
+
LIST = "#{Duby.source_path}/com/ribrdb/list.dhtml"
|
16
9
|
|
17
|
-
MODEL
|
18
|
-
DUBY_APP = 'com/ribrdb/DubyApp'
|
19
|
-
|
20
|
-
MODEL_DUBY = "#{SRC}/#{MODEL}.duby"
|
21
|
-
MODEL_CLASS = "#{WEB_INF_CLASSES}/#{MODEL}.class"
|
22
|
-
DUBY_APP_DUBY = "#{SRC}/#{DUBY_APP}.duby"
|
23
|
-
DUBY_APP_CLASS = "#{WEB_INF_CLASSES}/#{DUBY_APP}.class"
|
24
|
-
LIST = "#{SRC}/com/ribrdb/list.dhtml"
|
25
|
-
|
26
|
-
def dubyc(*files)
|
27
|
-
chdir(File.dirname(__FILE__) + '/src') do
|
28
|
-
files = files.join ' '
|
29
|
-
dest = '-d ../war/WEB-INF/classes'
|
30
|
-
dubyc = '../../../bin/dubyc'
|
31
|
-
options = "-I #{LIB} -p datastore"
|
32
|
-
orig_classpath = ENV['CLASSPATH']
|
33
|
-
ENV['CLASSPATH'] ||= ''
|
34
|
-
ENV['CLASSPATH'] += ":#{SERVLET}:#{APIS}:#{WEB_INF_CLASSES}"
|
35
|
-
sh %{#{dubyc} #{dest} #{options} #{files}}
|
36
|
-
ENV['CLASSPATH'] = orig_classpath
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
directory WEB_INF_CLASSES
|
41
|
-
|
42
|
-
file MODEL_CLASS => MODEL_DUBY do
|
43
|
-
dubyc("#{MODEL}.duby")
|
44
|
-
end
|
45
|
-
|
46
|
-
file DUBY_APP_CLASS => [DUBY_APP_DUBY, LIST, MODEL_CLASS] do
|
47
|
-
dubyc("#{DUBY_APP}.duby")
|
48
|
-
end
|
49
|
-
|
50
|
-
file WEB_XML => [WEB_INF_CLASSES, CONFIG_RU] do
|
51
|
-
builder = WebXmlBuilder.new do
|
52
|
-
eval IO.read(CONFIG_RU), nil, 'config.ru', 1
|
53
|
-
end
|
54
|
-
open(WEB_XML, 'w') do |webxml|
|
55
|
-
xml = AppEngine::Rack::XmlFormatter.format(builder.to_xml)
|
56
|
-
webxml.write(xml)
|
57
|
-
end
|
58
|
-
open(AEWEB_XML, 'w') do |aeweb|
|
59
|
-
xml = AppEngine::Rack::XmlFormatter.format(AppEngine::Rack.app.to_xml)
|
60
|
-
aeweb.write(xml)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
task :server => [WEB_XML, DUBY_APP_CLASS] do
|
65
|
-
sh "dev_appserver.rb #{WAR}"
|
66
|
-
end
|
67
|
-
|
68
|
-
task :upload => [WEB_XML, DUBY_APP_CLASS] do
|
69
|
-
sh "appcfg.rb update #{WAR}"
|
70
|
-
end
|
10
|
+
Rake::Task[DUBY_APP].enhance([LIST, MODEL])
|
71
11
|
|
12
|
+
task :app => DUBY_APP
|
72
13
|
task :default => :server
|
data/examples/appengine/Readme
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
Run rake to compile the application and start the development server
|
1
|
+
Run rake to compile the application and start the development server:
|
2
|
+
|
3
|
+
$ jruby -I `pwd`/../../lib -S rake
|
2
4
|
|
3
5
|
Requirements:
|
4
|
-
-
|
5
|
-
- Have jruby on your path so dubyc can run.
|
6
|
+
- jruby -S gem install google-appengine bitescript
|
6
7
|
|
7
8
|
Datastore API:
|
8
9
|
Model.get(key)
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'appengine-sdk'
|
2
|
+
require 'appengine-tools/appcfg'
|
3
|
+
require 'appengine-tools/dev_appserver'
|
4
|
+
require 'appengine-tools/web-xml'
|
5
|
+
require 'appengine-tools/xml-formatter'
|
6
|
+
require 'duby_task'
|
7
|
+
require 'java'
|
8
|
+
require 'open-uri'
|
9
|
+
require 'rake'
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
Duby.compiler_options.concat %w"-p datastore"
|
13
|
+
AppEngine::Development::JRubyDevAppserver::ARGV = []
|
14
|
+
module AppEngine::Rake
|
15
|
+
SERVLET = AppEngine::SDK::SDK_ROOT +
|
16
|
+
'/lib/shared/geronimo-servlet_2.5_spec-1.2.jar'
|
17
|
+
APIS = AppEngine::SDK::API_JAR
|
18
|
+
|
19
|
+
$CLASSPATH << SERVLET
|
20
|
+
$CLASSPATH << APIS
|
21
|
+
|
22
|
+
class AppEngineTask < Rake::Task
|
23
|
+
def initialize(*args, &block)
|
24
|
+
super
|
25
|
+
AppEngineTask.tasks << self
|
26
|
+
end
|
27
|
+
|
28
|
+
def init(src, war)
|
29
|
+
@src = src
|
30
|
+
@war = war
|
31
|
+
unless $CLASSPATH.include?(webinf_classes)
|
32
|
+
$CLASSPATH << webinf_classes
|
33
|
+
end
|
34
|
+
Duby.source_path = src
|
35
|
+
Duby.dest_path = webinf_classes
|
36
|
+
directory(webinf_classes)
|
37
|
+
directory(generated)
|
38
|
+
file_create dummy_config_ru do |t|
|
39
|
+
touch t.name
|
40
|
+
end
|
41
|
+
file_create gemfile do |t|
|
42
|
+
open(t.name, 'w') do |gems|
|
43
|
+
gems.puts('bundle_path ".gems/bundler_gems"')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
file web_xml => [webinf_classes, real_config_ru] do
|
47
|
+
config_ru = IO.read(real_config_ru)
|
48
|
+
builder = WebXmlBuilder.new do
|
49
|
+
eval config_ru, nil, 'config.ru', 1
|
50
|
+
end
|
51
|
+
open(web_xml, 'w') do |webxml|
|
52
|
+
xml = AppEngine::Rack::XmlFormatter.format(builder.to_xml)
|
53
|
+
webxml.write(xml)
|
54
|
+
end
|
55
|
+
open(aeweb_xml, 'w') do |aeweb|
|
56
|
+
xml = AppEngine::Rack::XmlFormatter.format(AppEngine::Rack.app.to_xml)
|
57
|
+
aeweb.write(xml)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
file build_status => [web_xml, dummy_config_ru, aeweb_xml, generated] do
|
61
|
+
open(build_status, 'w') do |status_file|
|
62
|
+
status = {
|
63
|
+
:config_ru => File.stat(dummy_config_ru).mtime,
|
64
|
+
:web_xml => File.stat(web_xml).mtime,
|
65
|
+
:aeweb_xml => File.stat(aeweb_xml).mtime,
|
66
|
+
}
|
67
|
+
status_file.write(status.to_yaml)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
task :server => [name, build_status] do
|
72
|
+
# Begin horrible hacks
|
73
|
+
if AppEngine::Development::JRubyDevAppserver::ARGV.empty?
|
74
|
+
AppEngine::Development::JRubyDevAppserver::ARGV << @war
|
75
|
+
end
|
76
|
+
class << AppEngine::Development::JRubyDevAppserver
|
77
|
+
def exec(*args)
|
78
|
+
sh *args
|
79
|
+
end
|
80
|
+
end
|
81
|
+
# End horrible hacks
|
82
|
+
check_for_updates
|
83
|
+
AppEngine::Development::JRubyDevAppserver.run([@war])
|
84
|
+
@done = true
|
85
|
+
@update_thread.join
|
86
|
+
end
|
87
|
+
task :upload => [name, build_status] do
|
88
|
+
AppEngine::Admin::JRubyAppCfg.main(['update', @war])
|
89
|
+
end
|
90
|
+
|
91
|
+
enhance([web_xml])
|
92
|
+
end
|
93
|
+
|
94
|
+
def real_prerequisites
|
95
|
+
prerequisites.map {|n| application[n, scope]}
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_for_updates
|
99
|
+
@update_thread = Thread.new do
|
100
|
+
# Give the server time to start
|
101
|
+
next_time = Time.now + 5
|
102
|
+
until @done
|
103
|
+
sleep_time = next_time - Time.now
|
104
|
+
sleep(sleep_time) if sleep_time > 0
|
105
|
+
next_time = Time.now + 1
|
106
|
+
update
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def update
|
112
|
+
updated = false
|
113
|
+
real_prerequisites.each do |dep|
|
114
|
+
if dep.needed?
|
115
|
+
dep.execute
|
116
|
+
updated = true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if updated
|
120
|
+
#touch aeweb_xml
|
121
|
+
open('http://localhost:8080/_ah/reloadwebapp')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def webinf_classes
|
126
|
+
@war + '/WEB-INF/classes'
|
127
|
+
end
|
128
|
+
|
129
|
+
def aeweb_xml
|
130
|
+
@war + '/WEB-INF/appengine-web.xml'
|
131
|
+
end
|
132
|
+
|
133
|
+
def web_xml
|
134
|
+
@war + '/WEB-INF/web.xml'
|
135
|
+
end
|
136
|
+
|
137
|
+
def real_config_ru
|
138
|
+
@src + '/config.ru'
|
139
|
+
end
|
140
|
+
|
141
|
+
def dummy_config_ru
|
142
|
+
@war + '/config.ru'
|
143
|
+
end
|
144
|
+
|
145
|
+
def generated
|
146
|
+
@war + '/WEB-INF/appengine-generated'
|
147
|
+
end
|
148
|
+
|
149
|
+
def build_status
|
150
|
+
generated + '/build_status.yaml'
|
151
|
+
end
|
152
|
+
|
153
|
+
def gemfile
|
154
|
+
@war + '/Gemfile'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def appengine_app(*args, &block)
|
160
|
+
deps = []
|
161
|
+
if args[-1].kind_of?(Hash)
|
162
|
+
hash = args.pop
|
163
|
+
arg = hash.keys[0]
|
164
|
+
deps = hash[arg]
|
165
|
+
args << arg
|
166
|
+
end
|
167
|
+
name, src, war = args
|
168
|
+
task = AppEngine::Rake::AppEngineTask.define_task(name => deps, &block)
|
169
|
+
src = File.expand_path(src || 'src')
|
170
|
+
war = File.expand_path(war || 'war')
|
171
|
+
task.init(src, war)
|
172
|
+
task
|
173
|
+
end
|
@@ -1,10 +1,42 @@
|
|
1
1
|
class DatastorePlugin
|
2
2
|
@models = {}
|
3
|
-
|
3
|
+
|
4
|
+
TypeMap = {
|
5
|
+
'Category' => 'String',
|
6
|
+
'Email' => 'String',
|
7
|
+
'Link' => 'String',
|
8
|
+
'PhoneNumber' => 'String',
|
9
|
+
'PostalAddress' => 'String',
|
10
|
+
'Text' => 'String',
|
11
|
+
'Blob' => 'byte[]',
|
12
|
+
'ShortBlob' => 'byte[]',
|
13
|
+
'Rating' => 'int',
|
14
|
+
'Integer' => 'int',
|
15
|
+
'Double' => 'double',
|
16
|
+
}
|
17
|
+
|
18
|
+
Defaults = {
|
19
|
+
'Rating' => '0',
|
20
|
+
'int' => '0',
|
21
|
+
'double' => '0.0',
|
22
|
+
}
|
23
|
+
|
24
|
+
Conversions = {
|
25
|
+
'Category' => 'getCategory',
|
26
|
+
'Email' => 'getEmail',
|
27
|
+
'Link' => 'getValue',
|
28
|
+
'PhoneNumber' => 'getNumber',
|
29
|
+
'PostalAddress' => 'getAddress',
|
30
|
+
'Text' => 'getValue',
|
31
|
+
'Blob' => 'getBytes',
|
32
|
+
'Integer' => 'intValue',
|
33
|
+
'Double' => 'doubleValue',
|
34
|
+
}
|
35
|
+
|
4
36
|
class ModelState
|
5
37
|
include Duby::AST
|
6
38
|
attr_reader :kind, :query, :read, :save, :transformer
|
7
|
-
|
39
|
+
|
8
40
|
def initialize(transformer, klass, parent, position, ast)
|
9
41
|
@transformer = transformer
|
10
42
|
@kind = klass.name.split('.')[-1]
|
@@ -13,13 +45,13 @@ class DatastorePlugin
|
|
13
45
|
init_read(parent, position, ast)
|
14
46
|
init_save(parent, position, ast)
|
15
47
|
end
|
16
|
-
|
48
|
+
|
17
49
|
def init_query(classname, parent, position, ast)
|
18
50
|
name = "#{classname}$Query"
|
19
51
|
@query = ClassDefinition.new(parent, position, name) do |classdef|
|
20
52
|
queryinit = <<-EOF
|
21
53
|
def initialize; end
|
22
|
-
|
54
|
+
|
23
55
|
def kind
|
24
56
|
"#{kind}"
|
25
57
|
end
|
@@ -54,29 +86,29 @@ class DatastorePlugin
|
|
54
86
|
[Duby::AST.type('com.google.appengine.ext.duby.db.DQuery'),
|
55
87
|
eval(classdef, queryinit)]
|
56
88
|
end
|
57
|
-
ast
|
89
|
+
ast << @query
|
58
90
|
end
|
59
|
-
|
91
|
+
|
60
92
|
def init_read(parent, position, ast)
|
61
93
|
@read = eval(parent, <<-EOF)
|
62
94
|
def _read_from(e:Entity)
|
63
95
|
end
|
64
96
|
EOF
|
65
|
-
@read.body =
|
66
|
-
ast
|
97
|
+
@read.body = Body.new(@read, position) {[]}
|
98
|
+
ast << @read
|
67
99
|
end
|
68
|
-
|
100
|
+
|
69
101
|
def init_save(parent, position, ast)
|
70
102
|
@save = eval(parent, <<-EOF)
|
71
103
|
def _save_to(e:Entity)
|
72
104
|
end
|
73
105
|
EOF
|
74
|
-
@save.body =
|
75
|
-
ast
|
106
|
+
@save.body = Body.new(@save, position) {[]}
|
107
|
+
ast << @save
|
76
108
|
end
|
77
|
-
|
109
|
+
|
78
110
|
def init_static(parent, ast)
|
79
|
-
ast
|
111
|
+
ast << eval(parent, <<-EOF)
|
80
112
|
import com.google.appengine.api.datastore.Entity
|
81
113
|
import com.google.appengine.api.datastore.Blob
|
82
114
|
import com.google.appengine.api.datastore.Category
|
@@ -97,7 +129,7 @@ class DatastorePlugin
|
|
97
129
|
m._read_from(Model._datastore.get(key))
|
98
130
|
m
|
99
131
|
end
|
100
|
-
|
132
|
+
|
101
133
|
def self.all
|
102
134
|
#{kind}__Query__.new
|
103
135
|
end
|
@@ -105,30 +137,48 @@ class DatastorePlugin
|
|
105
137
|
end
|
106
138
|
|
107
139
|
def eval(parent, src)
|
108
|
-
|
109
|
-
transformer.transform(ast.body_node, parent)
|
140
|
+
transformer.eval(src, __FILE__, parent)
|
110
141
|
end
|
111
142
|
|
112
143
|
def extend_query(code)
|
113
|
-
query.body
|
144
|
+
query.body << eval(query.body, code)
|
114
145
|
end
|
115
146
|
|
116
147
|
def extend_read(code)
|
117
148
|
code = 'e=nil;' + code
|
118
149
|
read.body.children.concat eval(read.body, code).children[1..-1]
|
119
150
|
end
|
120
|
-
|
151
|
+
|
121
152
|
def extend_save(code)
|
122
153
|
code = 'e=nil;' + code
|
123
154
|
save.body.children.concat eval(save.body, code).children[1..-1]
|
124
155
|
end
|
125
156
|
end
|
126
|
-
|
157
|
+
|
127
158
|
def self.find_class(node)
|
128
159
|
node = node.parent until Duby::AST::ClassDefinition === node
|
129
160
|
node
|
130
161
|
end
|
131
|
-
|
162
|
+
|
163
|
+
def self.to_datastore(type, value)
|
164
|
+
if TypeMap.include?(type)
|
165
|
+
"(#{value} ? #{type}.new(#{value}) : nil)"
|
166
|
+
else
|
167
|
+
value
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.from_datastore(type, value)
|
172
|
+
duby_type = TypeMap[type]
|
173
|
+
if duby_type
|
174
|
+
default = Defaults.fetch(type, "#{duby_type}(nil)")
|
175
|
+
conversion = Conversions[type]
|
176
|
+
"(#{value} ? #{type}(#{value}).#{conversion} : #{default})"
|
177
|
+
else
|
178
|
+
"#{type}(#{value})"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
132
182
|
Duby::AST.defmacro("property") do |transformer, fcall, parent|
|
133
183
|
result = Duby::AST::Body.new(parent, fcall.position) {[]}
|
134
184
|
klass = find_class(parent)
|
@@ -141,31 +191,42 @@ class DatastorePlugin
|
|
141
191
|
name = fcall.args_node.get(0).name
|
142
192
|
type = fcall.args_node.get(1).name
|
143
193
|
|
194
|
+
duby_type = TypeMap.fetch(type, type)
|
195
|
+
|
144
196
|
model.extend_query(<<-EOF)
|
145
|
-
def #{name}(value:#{
|
197
|
+
def #{name}(value:#{duby_type})
|
146
198
|
returns :void
|
147
|
-
_query.addFilter("#{name}", _eq_op, value)
|
199
|
+
_query.addFilter("#{name}", _eq_op, #{to_datastore(type, 'value')})
|
148
200
|
end
|
149
201
|
EOF
|
150
|
-
|
202
|
+
|
203
|
+
temp = transformer.tmp
|
204
|
+
|
151
205
|
model.extend_read(<<-EOF)
|
152
|
-
|
206
|
+
#{temp} = e.getProperty("#{name}")
|
207
|
+
@#{name} = #{from_datastore(type, temp)}
|
153
208
|
EOF
|
154
|
-
|
209
|
+
|
155
210
|
model.extend_save(<<-EOF)
|
156
|
-
e.setProperty("#{name}",
|
211
|
+
e.setProperty("#{name}", #{to_datastore(type, '@' + name)})
|
157
212
|
EOF
|
158
|
-
|
159
|
-
result
|
213
|
+
|
214
|
+
result << model.eval(parent, <<-EOF)
|
160
215
|
def #{name}
|
161
216
|
@#{name}
|
162
217
|
end
|
163
|
-
|
164
|
-
def #{name}=(value:#{
|
218
|
+
|
219
|
+
def #{name}=(value:#{duby_type})
|
165
220
|
@#{name} = value
|
166
221
|
end
|
167
222
|
EOF
|
168
223
|
|
169
224
|
result
|
170
225
|
end
|
171
|
-
|
226
|
+
|
227
|
+
def self.reset
|
228
|
+
@models = {}
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
Duby.plugins << DatastorePlugin
|