duby 0.0.2-java
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/History.txt +8 -0
- data/README.txt +39 -0
- data/Rakefile +13 -0
- data/bin/duby +9 -0
- data/bin/dubyc +9 -0
- data/bin/dubyp +9 -0
- data/examples/README +16 -0
- data/examples/appengine/Rakefile +72 -0
- data/examples/appengine/Readme +27 -0
- data/examples/appengine/config.ru +7 -0
- data/examples/appengine/lib/duby/plugin/datastore.rb +171 -0
- data/examples/appengine/src/com/google/appengine/ext/duby/db/Model.duby +132 -0
- data/examples/appengine/src/com/ribrdb/DubyApp.duby +28 -0
- data/examples/appengine/src/com/ribrdb/list.dhtml +15 -0
- data/examples/construction.duby +8 -0
- data/examples/edb.duby +3 -0
- data/examples/fib.duby +24 -0
- data/examples/fields.duby +22 -0
- data/examples/fractal.duby +57 -0
- data/examples/java_thing.duby +13 -0
- data/examples/simple_class.duby +12 -0
- data/examples/swing.duby +20 -0
- data/examples/tak.duby +15 -0
- data/examples/test.edb +9 -0
- data/javalib/JRubyParser.jar +0 -0
- data/lib/duby.rb +168 -0
- data/lib/duby/ast.rb +386 -0
- data/lib/duby/ast/call.rb +145 -0
- data/lib/duby/ast/class.rb +154 -0
- data/lib/duby/ast/flow.rb +332 -0
- data/lib/duby/ast/intrinsics.rb +56 -0
- data/lib/duby/ast/literal.rb +97 -0
- data/lib/duby/ast/local.rb +92 -0
- data/lib/duby/ast/method.rb +244 -0
- data/lib/duby/ast/structure.rb +62 -0
- data/lib/duby/ast/type.rb +93 -0
- data/lib/duby/c/compiler.rb +134 -0
- data/lib/duby/compiler.rb +282 -0
- data/lib/duby/jvm/compiler.rb +766 -0
- data/lib/duby/jvm/method_lookup.rb +193 -0
- data/lib/duby/jvm/source_compiler.rb +605 -0
- data/lib/duby/jvm/source_generator/builder.rb +387 -0
- data/lib/duby/jvm/source_generator/loops.rb +110 -0
- data/lib/duby/jvm/source_generator/precompile.rb +170 -0
- data/lib/duby/jvm/source_generator/typer.rb +11 -0
- data/lib/duby/jvm/typer.rb +131 -0
- data/lib/duby/jvm/types.rb +331 -0
- data/lib/duby/jvm/types/basic_types.rb +19 -0
- data/lib/duby/jvm/types/boolean.rb +11 -0
- data/lib/duby/jvm/types/enumerable.rb +63 -0
- data/lib/duby/jvm/types/factory.rb +155 -0
- data/lib/duby/jvm/types/floats.rb +70 -0
- data/lib/duby/jvm/types/integers.rb +110 -0
- data/lib/duby/jvm/types/intrinsics.rb +230 -0
- data/lib/duby/jvm/types/literals.rb +82 -0
- data/lib/duby/jvm/types/methods.rb +381 -0
- data/lib/duby/jvm/types/number.rb +92 -0
- data/lib/duby/nbcompiler.rb +29 -0
- data/lib/duby/old/compiler_old.rb +845 -0
- data/lib/duby/old/declaration.rb +72 -0
- data/lib/duby/old/mapper.rb +72 -0
- data/lib/duby/old/signature.rb +52 -0
- data/lib/duby/old/typer_old.rb +163 -0
- data/lib/duby/plugin/edb.rb +25 -0
- data/lib/duby/plugin/java.rb +42 -0
- data/lib/duby/plugin/math.rb +84 -0
- data/lib/duby/transform.rb +1028 -0
- data/lib/duby/typer.rb +369 -0
- data/test/TestUser.class +0 -0
- data/test/test_ast.rb +391 -0
- data/test/test_compilation.rb +98 -0
- data/test/test_java_typer.rb +199 -0
- data/test/test_javac_compiler.rb +58 -0
- data/test/test_jvm_compiler.rb +1770 -0
- data/test/test_math_plugin.rb +87 -0
- data/test/test_typer.rb +246 -0
- metadata +156 -0
data/History.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
= duby
|
2
|
+
|
3
|
+
* http://kenai.com/projects/duby
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Duby is a customizable programming language featuring static types,
|
8
|
+
local type inference and a heavily Ruby-inspired syntax. Duby
|
9
|
+
currently includes a typer/compiler backend for the JVM which can
|
10
|
+
output either JVM bytecode or Java source files.
|
11
|
+
|
12
|
+
== FEATURES/PROBLEMS:
|
13
|
+
|
14
|
+
* Ruby syntax
|
15
|
+
* Compiles to .class or .java
|
16
|
+
* Fast as Java
|
17
|
+
|
18
|
+
== SYNOPSIS:
|
19
|
+
|
20
|
+
duby <script.duby>
|
21
|
+
duby -e "inline script"
|
22
|
+
dubyc <script.duby>
|
23
|
+
dubyc -e "inline script" # produces dash_e.class
|
24
|
+
dubyc -java <script.duby>
|
25
|
+
dubyc -java -e "inline script" # produces dash_e.java
|
26
|
+
|
27
|
+
== REQUIREMENTS:
|
28
|
+
|
29
|
+
* JRuby 1.4RC2 or higher.
|
30
|
+
* BiteScript 0.0.5 or higher
|
31
|
+
|
32
|
+
== INSTALL:
|
33
|
+
|
34
|
+
* gem install duby
|
35
|
+
|
36
|
+
To build from source you should have a checkout of both jruby and
|
37
|
+
bitescript in Duby's parent directory. Run "ant jar-complete" in
|
38
|
+
jruby, then in the duby directory "ant bootstrap" followed by "ant"
|
39
|
+
should build it.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'java'
|
4
|
+
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
Rake::TestTask.new :test do |t|
|
8
|
+
t.libs << "lib"
|
9
|
+
# This is hacky, I know
|
10
|
+
t.libs.concat Dir["../bitescript*/lib"]
|
11
|
+
t.test_files = FileList["test/**/*.rb"]
|
12
|
+
java.lang.System.set_property("jruby.duby.enabled", "true")
|
13
|
+
end
|
data/bin/duby
ADDED
data/bin/dubyc
ADDED
data/bin/dubyp
ADDED
data/examples/README
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Duby: A Type-Inferred Ruby-Like JVM Language
|
2
|
+
|
3
|
+
Duby is an experimental project to create a JVM bytecode compiler for a
|
4
|
+
Ruby-like language that infers static types from argument declarations
|
5
|
+
and called methods. It is currently under development, but may eventually
|
6
|
+
be used to implement portions of JRuby, since Duby combines the terse,
|
7
|
+
neat syntax of Ruby with the performance of statically-typed Java
|
8
|
+
bytecode.
|
9
|
+
|
10
|
+
To compile the samples, run the following lines:
|
11
|
+
|
12
|
+
jruby lib/ruby/site_ruby/1.8/compiler/duby/compiler.rb <filename>
|
13
|
+
|
14
|
+
And to load and call them, use JRuby's Java integration:
|
15
|
+
|
16
|
+
CLASSPATH=. jruby -rjava -e "p Java::Foo.new.fib(35)"
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'appengine-sdk'
|
2
|
+
require 'appengine-tools/web-xml'
|
3
|
+
require 'appengine-tools/xml-formatter'
|
4
|
+
|
5
|
+
SRC = File.expand_path(File.dirname(__FILE__) + '/src')
|
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
|
12
|
+
|
13
|
+
WEB_INF_CLASSES = WAR + '/WEB-INF/classes'
|
14
|
+
WEB_XML = WAR + '/WEB-INF/web.xml'
|
15
|
+
AEWEB_XML = WAR + '/WEB-INF/appengine-web.xml'
|
16
|
+
|
17
|
+
MODEL = 'com/google/appengine/ext/duby/db/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
|
71
|
+
|
72
|
+
task :default => :server
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Run rake to compile the application and start the development server.
|
2
|
+
|
3
|
+
Requirements:
|
4
|
+
- Install the google-appengine gem (under MRI, not JRUBY)
|
5
|
+
- Have jruby on your path so dubyc can run.
|
6
|
+
|
7
|
+
Datastore API:
|
8
|
+
Model.get(key)
|
9
|
+
Model.delete(key)
|
10
|
+
Model.all -> Query
|
11
|
+
property foo, String # or any supported datastore type
|
12
|
+
# For numbers use Long or Double
|
13
|
+
|
14
|
+
instance.save
|
15
|
+
instance.key
|
16
|
+
|
17
|
+
instance.foo
|
18
|
+
instance.foo=
|
19
|
+
|
20
|
+
Query.count
|
21
|
+
Query.run -> Model[]
|
22
|
+
Query.first -> instance || nil
|
23
|
+
Query.sort(property_name)
|
24
|
+
Query.sort(property_name, true) # descending
|
25
|
+
Query.foo('foo').bar(3) # Only return instances where foo = 'foo' and bar = 3
|
26
|
+
Query.offset(10)
|
27
|
+
Query.limit(5)
|
@@ -0,0 +1,171 @@
|
|
1
|
+
class DatastorePlugin
|
2
|
+
@models = {}
|
3
|
+
|
4
|
+
class ModelState
|
5
|
+
include Duby::AST
|
6
|
+
attr_reader :kind, :query, :read, :save, :transformer
|
7
|
+
|
8
|
+
def initialize(transformer, klass, parent, position, ast)
|
9
|
+
@transformer = transformer
|
10
|
+
@kind = klass.name.split('.')[-1]
|
11
|
+
init_query(klass.name, parent, position, ast)
|
12
|
+
init_static(parent, ast)
|
13
|
+
init_read(parent, position, ast)
|
14
|
+
init_save(parent, position, ast)
|
15
|
+
end
|
16
|
+
|
17
|
+
def init_query(classname, parent, position, ast)
|
18
|
+
name = "#{classname}$Query"
|
19
|
+
@query = ClassDefinition.new(parent, position, name) do |classdef|
|
20
|
+
queryinit = <<-EOF
|
21
|
+
def initialize; end
|
22
|
+
|
23
|
+
def kind
|
24
|
+
"#{kind}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def first
|
28
|
+
it = _prepare.asIterator
|
29
|
+
if it.hasNext
|
30
|
+
e = Entity(it.next)
|
31
|
+
m = #{kind}.new
|
32
|
+
m._read_from(e)
|
33
|
+
m
|
34
|
+
else
|
35
|
+
#{kind}(nil)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def run
|
40
|
+
entities = _prepare.asList(_options)
|
41
|
+
models = #{kind}[entities.size]
|
42
|
+
it = entities.iterator
|
43
|
+
i = 0
|
44
|
+
while (it.hasNext)
|
45
|
+
e = Entity(it.next)
|
46
|
+
m = #{kind}.new
|
47
|
+
m._read_from(e)
|
48
|
+
models[i] = m
|
49
|
+
i += 1
|
50
|
+
end
|
51
|
+
models
|
52
|
+
end
|
53
|
+
EOF
|
54
|
+
[Duby::AST.type('com.google.appengine.ext.duby.db.DQuery'),
|
55
|
+
eval(classdef, queryinit)]
|
56
|
+
end
|
57
|
+
ast.children << @query
|
58
|
+
end
|
59
|
+
|
60
|
+
def init_read(parent, position, ast)
|
61
|
+
@read = eval(parent, <<-EOF)
|
62
|
+
def _read_from(e:Entity)
|
63
|
+
end
|
64
|
+
EOF
|
65
|
+
@read.body = @read.children[2] = Body.new(@read, position) {[]}
|
66
|
+
ast.children << @read
|
67
|
+
end
|
68
|
+
|
69
|
+
def init_save(parent, position, ast)
|
70
|
+
@save = eval(parent, <<-EOF)
|
71
|
+
def _save_to(e:Entity)
|
72
|
+
end
|
73
|
+
EOF
|
74
|
+
@save.body = @save.children[2] = Body.new(@save, position) {[]}
|
75
|
+
ast.children << @save
|
76
|
+
end
|
77
|
+
|
78
|
+
def init_static(parent, ast)
|
79
|
+
ast.children << eval(parent, <<-EOF)
|
80
|
+
import com.google.appengine.api.datastore.Entity
|
81
|
+
import com.google.appengine.api.datastore.Blob
|
82
|
+
import com.google.appengine.api.datastore.Category
|
83
|
+
import com.google.appengine.api.datastore.Email
|
84
|
+
import com.google.appengine.api.datastore.GeoPt
|
85
|
+
import com.google.appengine.api.datastore.IMHandle
|
86
|
+
import com.google.appengine.api.datastore.Key
|
87
|
+
import com.google.appengine.api.datastore.Link
|
88
|
+
import com.google.appengine.api.datastore.PhoneNumber
|
89
|
+
import com.google.appengine.api.datastore.PostalAddress
|
90
|
+
import com.google.appengine.api.datastore.Rating
|
91
|
+
import com.google.appengine.api.datastore.ShortBlob
|
92
|
+
import com.google.appengine.api.datastore.Text
|
93
|
+
import '#{kind}__Query__', '#{kind}$Query'
|
94
|
+
|
95
|
+
def self.get(key:Key)
|
96
|
+
m = #{kind}.new
|
97
|
+
m._read_from(Model._datastore.get(key))
|
98
|
+
m
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.all
|
102
|
+
#{kind}__Query__.new
|
103
|
+
end
|
104
|
+
EOF
|
105
|
+
end
|
106
|
+
|
107
|
+
def eval(parent, src)
|
108
|
+
ast = Duby::AST.parse_ruby(src, __FILE__)
|
109
|
+
transformer.transform(ast.body_node, parent)
|
110
|
+
end
|
111
|
+
|
112
|
+
def extend_query(code)
|
113
|
+
query.body.children << eval(query.body, code)
|
114
|
+
end
|
115
|
+
|
116
|
+
def extend_read(code)
|
117
|
+
code = 'e=nil;' + code
|
118
|
+
read.body.children.concat eval(read.body, code).children[1..-1]
|
119
|
+
end
|
120
|
+
|
121
|
+
def extend_save(code)
|
122
|
+
code = 'e=nil;' + code
|
123
|
+
save.body.children.concat eval(save.body, code).children[1..-1]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.find_class(node)
|
128
|
+
node = node.parent until Duby::AST::ClassDefinition === node
|
129
|
+
node
|
130
|
+
end
|
131
|
+
|
132
|
+
Duby::AST.defmacro("property") do |transformer, fcall, parent|
|
133
|
+
result = Duby::AST::Body.new(parent, fcall.position) {[]}
|
134
|
+
klass = find_class(parent)
|
135
|
+
unless @models[klass]
|
136
|
+
@models[klass] = ModelState.new(
|
137
|
+
transformer, klass, parent, fcall.position, result)
|
138
|
+
end
|
139
|
+
model = @models[klass]
|
140
|
+
|
141
|
+
name = fcall.args_node.get(0).name
|
142
|
+
type = fcall.args_node.get(1).name
|
143
|
+
|
144
|
+
model.extend_query(<<-EOF)
|
145
|
+
def #{name}(value:#{type})
|
146
|
+
returns :void
|
147
|
+
_query.addFilter("#{name}", _eq_op, value)
|
148
|
+
end
|
149
|
+
EOF
|
150
|
+
|
151
|
+
model.extend_read(<<-EOF)
|
152
|
+
@#{name} = #{type}(e.getProperty("#{name}"))
|
153
|
+
EOF
|
154
|
+
|
155
|
+
model.extend_save(<<-EOF)
|
156
|
+
e.setProperty("#{name}", @#{name})
|
157
|
+
EOF
|
158
|
+
|
159
|
+
result.children << model.eval(parent, <<-EOF)
|
160
|
+
def #{name}
|
161
|
+
@#{name}
|
162
|
+
end
|
163
|
+
|
164
|
+
def #{name}=(value:#{type})
|
165
|
+
@#{name} = value
|
166
|
+
end
|
167
|
+
EOF
|
168
|
+
|
169
|
+
result
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import com.google.appengine.api.datastore.DatastoreServiceFactory
|
2
|
+
import com.google.appengine.api.datastore.Entity
|
3
|
+
import com.google.appengine.api.datastore.EntityNotFoundException
|
4
|
+
import com.google.appengine.api.datastore.Key
|
5
|
+
import com.google.appengine.api.datastore.KeyFactory
|
6
|
+
import com.google.appengine.api.datastore.Query
|
7
|
+
import 'Builder', 'com.google.appengine.api.datastore.FetchOptions$Builder'
|
8
|
+
import 'FilterOperator', 'com.google.appengine.api.datastore.Query$FilterOperator'
|
9
|
+
import 'SortDirection', 'com.google.appengine.api.datastore.Query$SortDirection'
|
10
|
+
|
11
|
+
class DQuery
|
12
|
+
def initialize
|
13
|
+
@query = Query.new(kind)
|
14
|
+
end
|
15
|
+
|
16
|
+
def kind
|
17
|
+
"foo"
|
18
|
+
end
|
19
|
+
|
20
|
+
def limit(l:int)
|
21
|
+
returns :void
|
22
|
+
if @options
|
23
|
+
@options.limit(l)
|
24
|
+
else
|
25
|
+
@options = Builder.withLimit(l)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def offset(o:int)
|
30
|
+
returns :void
|
31
|
+
if @options
|
32
|
+
@options.offset(o)
|
33
|
+
else
|
34
|
+
@options = Builder.withOffset(o)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def sort(name:String)
|
39
|
+
sort(name, false)
|
40
|
+
end
|
41
|
+
|
42
|
+
def sort(name:String, descending:boolean)
|
43
|
+
returns :void
|
44
|
+
if descending
|
45
|
+
@query.addSort(name, _desc)
|
46
|
+
else
|
47
|
+
@query.addSort(name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def count
|
52
|
+
_prepare.countEntities
|
53
|
+
end
|
54
|
+
|
55
|
+
def _query
|
56
|
+
@query
|
57
|
+
end
|
58
|
+
|
59
|
+
def _options
|
60
|
+
if @options.nil?
|
61
|
+
@options = Builder.withOffset(0)
|
62
|
+
end
|
63
|
+
@options
|
64
|
+
end
|
65
|
+
|
66
|
+
def _prepare
|
67
|
+
Model._datastore.prepare(@query)
|
68
|
+
end
|
69
|
+
|
70
|
+
def _eq_op
|
71
|
+
FilterOperator.valueOf("EQUAL")
|
72
|
+
end
|
73
|
+
|
74
|
+
def _desc
|
75
|
+
SortDirection.valueOf("DESCENDING")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Model
|
80
|
+
def initialize
|
81
|
+
end
|
82
|
+
|
83
|
+
def self._datastore
|
84
|
+
unless @service
|
85
|
+
@service = DatastoreServiceFactory.getDatastoreService
|
86
|
+
end
|
87
|
+
@service
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.delete(key:Key)
|
91
|
+
returns :void
|
92
|
+
keys = Key[1]
|
93
|
+
keys[0] = key
|
94
|
+
Model._datastore.delete(keys)
|
95
|
+
end
|
96
|
+
|
97
|
+
def kind
|
98
|
+
getClass.getSimpleName
|
99
|
+
end
|
100
|
+
|
101
|
+
def key
|
102
|
+
if @entity
|
103
|
+
@entity.getKey
|
104
|
+
else
|
105
|
+
Key(nil)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def save
|
110
|
+
Model._datastore.put(to_entity)
|
111
|
+
end
|
112
|
+
|
113
|
+
def delete
|
114
|
+
returns :void
|
115
|
+
Model.delete(key)
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_entity
|
119
|
+
unless @entity
|
120
|
+
@entity = Entity.new(kind)
|
121
|
+
end
|
122
|
+
_save_to(@entity)
|
123
|
+
@entity
|
124
|
+
end
|
125
|
+
|
126
|
+
# protected
|
127
|
+
def _save_to(e:Entity)
|
128
|
+
end
|
129
|
+
|
130
|
+
def _read_from(e:Entity)
|
131
|
+
end
|
132
|
+
end
|