Rave: Back at it
Anyway, I'll post more on Rave pretty soon. In the mean time, check it out on Github, for more info. Particularly the README.
This will add the plugin to your vendor/plugins folder, and it will create a vendor/jars folder. Then, for any Java jar that you want to be accessible from your JRuby code, just drop the jar into that vendor/jars folder, and it will automatically get required at startup.script/plugin install git://github.com/diminish7/vendor_jars.git
sudo jruby -S gem install rave
jruby -S rave create [robot_name] [options]
jruby -S rave create appropriate-casey
jruby -S rave create appropriate-casey image_url=http://myimageurl/avatar.png
def document_changed(event, context)
# Do some stuff
end
def document_changed(event, context)
unless event.modified_by == "appropriate-casey@appspot.com" ||
event.modified_by == "spelly@gwave.com"
context.blips.values.each do |blip|
if blip.content
new_sentence = true
blip.content.length.times do |index|
range = index..index+1
char = blip.content[index, 1]
if char =~ /[A-Z]/ && !new_sentence
blip.set_text_in_range(range, char.downcase)
elsif char =~ /[a-z]/ && new_sentence
blip.set_text_in_range(range, char.upcase)
elsif char == "!"
if new_sentence
blip.delete_range(range)
else
blip.set_text_in_range(range, ".")
end
end
new_sentence = (char =~ /\.!?/ || (char =~ /\s/ && new_sentence))
end
end
end
end
end
jruby -S rave war
path/to/appengine_sdk/bin/dev_server tmp/war
path/to/appengine_sdk/bin/appcfg update tmp/war
sudo jruby -S gem install moonstoneNote that if you are on Windows, drop the "sudo". Also, for the record, no one's ever tested Moonstone on Windows. But since it's all JRuby and Java, there shouldn't be any issues...
That's it in a nutshell. There are some more examples in the README on github, and more documentation is coming soon.
class SimplestEngine def doc_from(record)
doc = Lucene::Document::Doc.new
doc.add_field('name', record[:name])
doc.add_field('desc', record[:description])
doc
end
def analyzer
@analyzer ||= Lucene::Analysis::WhitespaceAnalyzer.new
end
end
# We can now instantiate the engine
engine = SimplestEngine.new
# and create an index of some data
records = [
{:name => "Moonstone", :description => "A simple JRuby wrapper around Lucene"},
{:name => "Foo", :description => "A search engine based on Moonstone"}
]
# By convention the index method accepts an Enumerable that yields hashes
engine.index(records)
#Search for data
q = Lucene::Search::TermQuery.new("name", "Moonstone")
documents = engine.search(q)
documents.each {|d| puts d['name']}
<html>Which would be rendered as:
<head>
<title>Hello World</title>
</head>
<body>
<span component="if" condition="true">
Body of 'if' component
</span>
<span component="elsif" condition="true">
Body of 'elsif' component
</span>
<span component="else">
Body of 'else' component
</span>
</body>
</html>
<html>The 'component' attribute can either refer to a built in control flow structure, such as 'if', or 'foreach', or it can refer to a partial, so you can embed mini-beholder templates in your main template. There is also a 'yield' component, so each component can act like a layout, generating it's HTML, and then yielding the content within the component node in the template.
<head>
<title>Hello World</title>
</head>
<body>
Body of 'if' component
</body>
</html>
<html>And a partial called simple_component.beh like this:
<head>
<title>Hello World</title>
</head>
<body>
<span component="simple_component" message_class="beholder" />
</body>
</html>
<p class="prop:message_class">What's up, world?</p>It would be rendered like this:
The 'prop:' prefixed attributes get evaluated as (in this order) a) the value of the parent component's attribute with that name, b) the value of a local variable of that name, or c) a method in the helper class. (Note that I've only implemented a) right now... so you'll just have to trust me that that's where I'm going.)<html>
<head>
<title>Hello World</title>
</head>
<body>
<p class="beholder">What's up, world?</p>
</body>
</html>
new_gameThat generates almost all the facts and rules for the game. There are a few rules that are implied by the combination of these rules - since "O" is immediately after "L", and "News" is sometime after "L", then "News" must be at least 2 after "L". So that's next: figure out how to imply rules from combinations of explicit rules.
called "Broadcast"
described_as("Seven consecutive time slots... etc")
with_property "Position"
with_range 1, 7
for_entities "G", "H", "L", "O", "P", "S", "News"
new_question
described_as "If G is played 2nd... etc"
with_fact "G", "Position", :is, 2
determines ["News", "H", "L", "O", "S"], "Position", :is, 3
#L must be played immediately before O
new_rule "L", :before, "O", 1
#The news tape must be played at some time after L
new_rule "News", :after, "L"
#There must be exactly two time slots between G and P, regardless of
# whether G comes before P or whether G comes after P
new_rule "G", :separated_by, "P", 2
evaluate
#Set up game descriptionThis replaces the first 70 lines of the game. It sets up the game, and adds all the standard rules, like one-place-at-a-time rules, mutual-exclusion rules, and last-available-position rules.
new_game
called "Broadcast"
described_as(
"Seven consecutive time slots for a broadcast, numbered in chronological order 1 through 7, will be filled by six song tapes - G, H, L, O, P, S - and exactly one news tape. Each tape is to be assigned to a different time slot, and no tape is longer than any other tape. The broadcast is subject to the following restrictions:)
- L must be played immediately before O
- The news tape must be played at some time after L
- There must be exactly two time slots between G and P, regardless of whether G comes before P or whether G comes after P"
with_property "Position"
with_range 1, 7
for_entities "G", "H", "L", "O", "P", "S", "News"
#Create the questions
new_question
described_as "If G is played second, which one of the following tapes must be played third?"
with_fact "G", "Position", :is, 2
determines ["News", "H", "L", "O", "S"], "Position", :is, 3
"Henry's lesson is later in the schedule than Janet's"might turn into something like
new_rule "Henry", "Position", :after, "Janet"Which will then get broken up into the 20 or so rules that that implies behind the scenes.