Eva
Eva is an effortless event driven micro framework that runs on Ruby (cruby and jruby) through eventmachine with a different syntax.
The common problem with EventMachine is to deal with callbacks, fortunately thanks to
people like Ilya Grigorik and things
like em-synchrony make this job is a little simpler but
a bit far to be native like in javascript.
So here my idea to make experiment and try to figure out a new way to write better our applications following the nature of the reactor pattern with a special focus on simplicity and clearity.
Overview
It's pure ruby, no lexers and parsers. If you want a fast tast on how it looks like, please see emitter
The idea behind it is to build all our apps only using two ruby objects: namespaces and objectspace
Like in languages like javascript or lua if we have:
var hello = function(){ console.log('Hello!') }in order to invoke our function we should use hello() otherwise using only hello we will get
the Function object.
In that way is simple to chain functions and do things like:
var callback = function(obj){ Notifier.sendEmail(obj) }
doExpensiveTask(var1, var2, callback)So I applied the same rule on Ruby:
unless you don't provide method arguments, invoking a method will get a Method Object instead of the result of the method itself
Here an example:
namespace :Greater,
say: ->(text) { p text }
Greater.say 'Hello World!'
=> "Hello World!"
Greater.say
=> #<Method: Module(Greater)#say!>The main difference is that using objectspace and namespace we create
unbounded methods, we can still call directly these methods but appending ! (bang) prefix
or using [] or using .call
Greater.say[]
Greater.say!
Greater.say.callSo where this can help us?
Look a the following examples:
namespace :Circle,
area: ->(n) do
Math::PI * n * n
end,
big_calc: -> do
perform_a_big_calc
end
LotOfNumbers.each &Circle.area
defer Circle.big_calc
set_timeout 10, Circle.big_calcNamespaces
Namespaces are simply module functions a namespace looks like:
namespace :Greater,
say: ->(text) { p [:say, text] }You can extend it from another place simply invoking it:
namespace :Greater,
say_hello: -> do
say 'Hello There!'
endRemember that it's ruby so you can include extend other objects like:
module OldModule
include Greater
endSince is a module function remember you can invoke methods directly:
Greater.say 'Hello World'
Greater.say_hello! # <<<<< REMBEMBER THAT IF WE DON'T HAVE ARGUMENT TO ADD A ! or []Objectspace
Are exactly ruby classes with no exception and the structure is identical to the module
objectspace :Greater,
say: ->(text){ p [:say, text] }Also here we can add other methods whenever and wherever we want:
namespace :Greater,
say_hello: -> do
say 'Hello There!'
endSo now we can create our Object:
greater = Greater.new
greater.say 'Hello world'
greater.say_hello! # <<<<< REMBEMBER THAT IF WE DON'T HAVE ARGUMENT TO ADD A ! or []Constructors, Private Methods, Attributes ...
In eva there are some special keys:
-
initialize: used only for objects -
include: to include a module -
extend: to extend an object with the given module -
attr_reader, attr_writer, attr_accessor, attr: to create attributes for objects and spaces alias_method
Finally if you need to create private methods you can do that only prefixing with _
Example:
objectspace :Tester,
attr_reader: [:a, :b, :c],
attr_writer: [:d, :e, :f],
attr_accessor: [:g, :h, :i],
initialize: -> do
@a, @b, @c = 1, 2, 3
f = foo
say
end,
foo: -> { p [:alias, :bar] },
alias_method: { :bar => :foo },
say: MyMod.say, # this is a delegate
Tester.newEvented
As mentioned before, the aim of this project is play nice with eventmachine,
so in eva we extended the main Object with few and useful delegator:
:add_periodic_timer, :add_timer, :add_shutdown_hook, :cancel_timer,
:defer, :defers_finished?, :fork_reactor, :next_tick,
:popen, :reactor_running?, :reactor_thread?,
:schedule, :spawn, :system, :tick_loopand few aliases:
alias :set_interval :add_periodic_timer
alias :set_timeout :add_timer
alias :clear_interval :cancel_timer
alias :clear_timeout :cancel_timerInstallation
Add this line to your application's Gemfile:
gem 'eva'
And then execute:
$ bundle
Or install it yourself as:
$ gem install eva
Usage
You can use eva syntax in all your projects simply requiring it, if you plan to use evented code
so set_timeout, defer ... you should use eva executable:
eva examples/timers.rbContributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request
Copyright
Copyright (C) 2013 Davide D'Agostino - @DAddYE
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.