mikka 1.0.0-universal-darwin-11

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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ /*.gem
2
+ /.bundle
3
+ /Gemfile.lock
4
+ /pkg/*
5
+ /ext
6
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use jruby-1.6.3@mikka
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/README.mdown ADDED
@@ -0,0 +1,33 @@
1
+ # Mikka
2
+
3
+ Mikka is a thin Ruby wrapper around Akka. It makes Akka's Java API more pleasing to the Rubyist's eye.
4
+
5
+ ## Work in progress
6
+
7
+ Mikka is a work in progress, but currently used in production. It currently mostly scratches my own itchs, but improvement suggestions and patches are welcome.
8
+
9
+ Check out the `examples` directory for the basics. Start with the `hello_world.rb` example, it is extensively documented and goes through the basics.
10
+
11
+ If you make something that can serve as a useful illustration of some concept, please contribute by sending a patch.
12
+
13
+ ## Requirements
14
+
15
+ Only tested in JRuby 1.6.3 and Ruby 1.9 mode (add `jruby --1.9` or set `JRUBY_OPTS='--1.9`).
16
+
17
+ The required Akka and Scala JARs are loaded from the [akka-actor-jars](https://rubygems.org/gems/akka-actor-jars) and [scala-library-jars](https://rubygems.org/gems/scala-library-jars) wrapper gems.
18
+
19
+ ## Installation
20
+
21
+ gem install mikka
22
+
23
+ ## Contributors
24
+
25
+ Theo Hultberg, [@iconara](http://twitter.com/iconara)
26
+
27
+ ## License
28
+
29
+ Mikka is licensed under the Apache 2 license, the same as Akka. See http://akka.io/docs/akka/1.1.2/project/licenses.html
30
+
31
+ ## Mikka?
32
+
33
+ Mikka is a glacier close to the Akka massive.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ require 'bundler'
4
+
5
+
6
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'bundler/setup'
6
+ require 'mikka'
7
+
8
+ # 0.
9
+ # The numbers at the top of the comment blocks follow the flow of the
10
+ # application, read them in order to see the sequence of events.
11
+
12
+ # 1.
13
+ # The simplest way to create an actor is to do it with a block. The block
14
+ # will receive each message and execute in the scope of an actor object (so
15
+ # `context` will be available -- more on that later).
16
+ #
17
+ # The variable `phil` will not refer directly to an actor instance, but to an
18
+ # `ActorRef`. There are many reasons for this, and for the full picture refer
19
+ # to the Akka documentation. The short explanation is that it makes it
20
+ # possible to restart and replace the actor without the clients knowing that
21
+ # the actor instance was changed, and it makes remote actors transparent.
22
+ phil = Mikka.actor do |msg|
23
+ # 8.
24
+ # Ruby doesn't have pattern matching, but `case` is usually enough. If you
25
+ # Have separate classes for your messages you can match on class.
26
+ case msg
27
+ when Introduction
28
+ # 9.
29
+ # The `Introduction` class has a field called `to_whom` that contains a
30
+ # reference to an actor that someone want to introduce us to. Let's send
31
+ # that actor a `Greeting`.
32
+ msg.to_whom << Greeting.new('Hello, dear sir.')
33
+ when Greeting
34
+ puts "Received greeting: #{msg.body}"
35
+ # 12.
36
+ # The reply got routed back to this actor. Now we want to shut down this
37
+ # actor too, so that the application can shut down.
38
+ context.exit
39
+ end
40
+ end
41
+
42
+ # 2.
43
+ # If you need more control over your actor's life cycle, or want to create
44
+ # more than one of the same you can can declare a subclass of Mikka::Actor.
45
+ # The #receive method is called for each message the actor receives. You can
46
+ # do things when the actor starts by implementing #pre_start, and when the
47
+ # actor stops by implementing #post_stop.
48
+ #
49
+ # Don't create instances of this class yourself, an error will be raised if
50
+ # it's done in the wrong way, see below for how it's supposed to be done.
51
+ class Replier < Mikka::Actor
52
+ def receive(msg)
53
+ case msg
54
+ when Greeting
55
+ puts "Received greeting: #{msg.body}"
56
+ # 10.
57
+ # To reply to a message without having to explicitly refer to the sender
58
+ # use #reply (you can, however, store the sender and reply later if you
59
+ # want, it is available through `context.sender.get`).
60
+ #
61
+ # A word of caution: the sender is not always set, for example when the
62
+ # message was sent from a non-actor context like in 6. Also, the Scala
63
+ # API sets the sender implicitly in a way that is not possible in Java
64
+ # or Ruby, and even if Mikka does it's best to emulate the Scala way,
65
+ # it's not foolproof. If you want to guard agains errors when replying
66
+ # you can use #reply_safe instead of #reply. It will return true if the
67
+ # message could be sent, and false otherwise.
68
+ context.reply(Greeting.new('Why, hello old chap.'))
69
+ # 11.
70
+ # Now we're through with this actor, so we shut it down.
71
+ context.exit
72
+ end
73
+ end
74
+ end
75
+
76
+ # 3.
77
+ # This is how you create an actor reference from a subclass of Mikka::Actor.
78
+ # Creating the instance this way makes sure that the actor is set up correctly
79
+ # (refer to the Akka documentation as to why it works this way).
80
+ sam = Mikka.actor_of(Replier)
81
+
82
+ # 4.
83
+ # Messages can be anything, but if your messages are more complex than a
84
+ # simple string or symbol you are best off declaring a proper class to
85
+ # encapsulate them. `Struct` is convenient in this case (but creates mutable
86
+ # objects, consider using the `immutable_struct` gem instead).
87
+ class Introduction < Struct.new(:to_whom); end
88
+ class Greeting < Struct.new(:body); end
89
+
90
+ # 5.
91
+ # An actor must be started before it can be used!
92
+ phil.start
93
+ sam.start
94
+
95
+ # 6.
96
+ # And finally, this is how to send a message to an actor. In Erlang and Scala
97
+ # it is done with !, but that operator is not overridable in Ruby, so we have
98
+ # to make do with <<. The Akka Java API defines #send_one_way (actually
99
+ # sendOneWay, but JRuby fixes the casing for us), which can also be used.
100
+ #
101
+ # Here we send a message to `phil`, the message is an object that contains a
102
+ # reference to the actor `sam`.
103
+ phil << Introduction.new(sam)
104
+
105
+ # 7.
106
+ # The application will keep running until the last actor is dead. If you want
107
+ # to force shutdown you can use `Mikka.registry.shutdown_all`.
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'bundler/setup'
6
+ require 'mikka'
7
+
8
+
9
+ worker1 = Mikka.actor { |msg| puts "Worker 1 working on #{msg}" }
10
+ worker2 = Mikka.actor { |msg| puts "Worker 2 working on #{msg}" }
11
+ balancer = Mikka.load_balancer(:actors => [worker1, worker2])
12
+
13
+ 10.times do |i|
14
+ balancer << "item #{i}"
15
+ end
16
+
17
+ balancer << Mikka::Messages.broadcast("a message to everyone")
18
+ balancer << Mikka::Messages.poison_pill
19
+
20
+ Mikka.registry.shutdown_all
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'bundler/setup'
6
+ require 'mikka'
7
+
8
+
9
+ class Worker < Mikka::Actor
10
+ def receive(message)
11
+ puts "#{context.uuid} Work on #{message}"
12
+ end
13
+ end
14
+
15
+ balancer = Mikka.load_balancer(:type => Worker, :count => 4)
16
+
17
+ 10.times do |i|
18
+ balancer << "item #{i}"
19
+ end
20
+
21
+ balancer << Mikka::Messages.broadcast("a message to everyone")
22
+
23
+ Mikka.registry.shutdown_all
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'bundler/setup'
6
+ require 'mikka'
7
+
8
+
9
+ actor = Mikka.actor do |message|
10
+ case message
11
+ when 'hi'
12
+ puts "hello yourself"
13
+ when 'goodbye'
14
+ puts "adieu"
15
+ context.exit
16
+ else
17
+ puts "sorry, come again?"
18
+ end
19
+ end
20
+
21
+ actor.start
22
+ actor << 'hi'
23
+ actor << 'hello'
24
+ actor << 'goodbye'
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'bundler/setup'
6
+ require 'mikka'
7
+
8
+
9
+ class Stallone < Mikka::Actor
10
+ def receive(message)
11
+ context.exit if message == 'punch!'
12
+ end
13
+ end
14
+
15
+ stallone = Mikka.actor_of(Stallone).start
16
+ stallone << 'punch!'
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'bundler/setup'
6
+ require 'mikka'
7
+
8
+
9
+ class Worker < Mikka::Actor
10
+ life_cycle :permanent
11
+
12
+ def pre_start
13
+ puts "#{context.id} starting"
14
+ end
15
+
16
+ def pre_restart(reason)
17
+ puts "#{context.id} restarting"
18
+ end
19
+
20
+ def post_restart(reason)
21
+ puts "#{context.id} restarted"
22
+ end
23
+
24
+ def post_stop
25
+ puts "#{context.id} stopped"
26
+ end
27
+
28
+ def receive(message)
29
+ raise java.lang.Exception.new('Oh, shucks') if message == 'hard work'
30
+ puts "#{context.id} Work on #{message}"
31
+ end
32
+ end
33
+
34
+ class Manager < Mikka::Actor
35
+ fault_handling :strategy => :all_for_one, :trap => [java.lang.Exception], :max_retries => 3, :time_range => 3000
36
+
37
+ def pre_start
38
+ @worker1 = Mikka.actor_of { Worker.new }
39
+ @worker2 = Mikka.actor_of { Worker.new }
40
+ @worker1.id = 'worker1'
41
+ @worker2.id = 'worker2'
42
+ context.start_link(@worker1)
43
+ context.start_link(@worker2)
44
+ @worker1 << 'simple work'
45
+ @worker2 << 'hard work'
46
+ @worker2 << 'simple work'
47
+ @worker2 << 'simple work'
48
+ @worker2 << 'hard work'
49
+ @worker2 << 'simple work'
50
+ @worker2 << 'simple work'
51
+ @worker2 << 'simple work'
52
+ end
53
+ end
54
+
55
+ manager = Mikka.actor_of(Manager).start
data/lib/akka.rb ADDED
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'java'
4
+ require 'akka-actor-jars'
5
+
6
+
7
+ module Akka
8
+ module Actor
9
+ include_package 'akka.actor'
10
+
11
+ import 'akka.actor.ActorRef'
12
+ import 'akka.actor.UntypedActor'
13
+
14
+ class UntypedActor
15
+ def self.create(*args)
16
+ new(*args)
17
+ end
18
+ end
19
+ end
20
+
21
+ module Config
22
+ include_package 'akka.config'
23
+ end
24
+
25
+ module Routing
26
+ include_package 'akka.routing'
27
+ end
28
+ end
data/lib/mikka.rb ADDED
@@ -0,0 +1,161 @@
1
+ # encoding: utf-8
2
+
3
+ require 'java'
4
+ require 'akka'
5
+
6
+
7
+ module Mikka
8
+ import java.util.Arrays
9
+
10
+ def self.actor_of(*args, &block)
11
+ Akka::Actor::Actors.actor_of(*args, &block)
12
+ end
13
+
14
+ def self.actor(&block)
15
+ Akka::Actor::Actors.actor_of { ProcActor.new(&block) }
16
+ end
17
+
18
+ def self.registry
19
+ Akka::Actor::Actors.registry
20
+ end
21
+
22
+ def self.current_actor
23
+ Thread.current[:mikka_current_actor]
24
+ end
25
+
26
+ module Messages
27
+ def self.broadcast(message)
28
+ Akka::Routing::Routing::Broadcast.new(message)
29
+ end
30
+
31
+ def self.poison_pill
32
+ Akka::Actor::Actors.poison_pill
33
+ end
34
+ end
35
+
36
+ module RubyesqueActorCallbacks
37
+ def receive(message); end
38
+ def pre_start; end
39
+ def post_stop; end
40
+ def pre_restart(reason); end
41
+ def post_restart(reason); end
42
+
43
+ def onReceive(message); receive(message); end
44
+ def preStart; super; pre_start; end
45
+ def postStop; super; post_stop; end
46
+ def preRestart(reason); super; pre_restart(reason); end
47
+ def postRestart(reason); super; post_restart(reason); end
48
+ end
49
+
50
+ module ImplicitSender
51
+ def capture_current_actor
52
+ Thread.current[:mikka_current_actor] = context
53
+ yield
54
+ ensure
55
+ Thread.current[:mikka_current_actor] = nil
56
+ end
57
+
58
+ def self.included(mod)
59
+ mod.class_eval do
60
+ [:onReceive, :preStart, :postStop, :preRestart, :postRestart].each do |method_name|
61
+ actual_method_name = :"__actual_#{method_name}"
62
+ alias_method actual_method_name, method_name
63
+ define_method method_name do |*args|
64
+ capture_current_actor do
65
+ send(actual_method_name, *args)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ module SupervisionDsl
74
+ module ClassMethods
75
+ def fault_handling(config)
76
+ trap = config[:trap].map { |e| e.java_class }
77
+ max_retries = config.fetch(:max_retries, 5)
78
+ time_range = config.fetch(:time_range, 5000)
79
+ case config[:strategy]
80
+ when :all_for_one
81
+ @fault_handling_strategy = Akka::Config::Supervision::AllForOneStrategy.new(trap, max_retries, time_range)
82
+ when :one_for_one
83
+ @fault_handling_strategy = Akka::Config::Supervision::OneForOneStrategy.new(trap, max_retries, time_range)
84
+ else
85
+ raise ArgumentError, 'strategy must be one of :all_for_one or :one_for_one'
86
+ end
87
+ end
88
+
89
+ def registered_fault_handling_strategy
90
+ @fault_handling_strategy
91
+ end
92
+
93
+ def life_cycle(type)
94
+ @life_cycle = case type
95
+ when :permanent then Akka::Config::Supervision.permanent
96
+ when :temporary then Akka::Config::Supervision.temporary
97
+ when :undefined then Akka::Config::Supervision.undefined_life_cycle
98
+ else raise ArgumentError, 'type must be one of :permanent, :temporary or :undefined'
99
+ end
100
+ end
101
+
102
+ def registered_life_cycle
103
+ @life_cycle
104
+ end
105
+ end
106
+
107
+ module InstanceMethods
108
+ def initialize(*args)
109
+ super
110
+ if self.class.registered_fault_handling_strategy
111
+ context.fault_handler = self.class.registered_fault_handling_strategy
112
+ end
113
+ if self.class.registered_life_cycle
114
+ context.life_cycle = self.class.registered_life_cycle
115
+ end
116
+ end
117
+ end
118
+
119
+ def self.included(m)
120
+ m.extend(ClassMethods)
121
+ m.include(InstanceMethods)
122
+ end
123
+ end
124
+
125
+ class Actor < Akka::Actor::UntypedActor
126
+ include SupervisionDsl
127
+ include RubyesqueActorCallbacks
128
+ include ImplicitSender
129
+ end
130
+
131
+ class ProcActor < Actor
132
+ def initialize(&receive)
133
+ define_singleton_method(:receive, receive)
134
+ end
135
+ end
136
+
137
+ def self.load_balancer(options={})
138
+ actors = options[:actors]
139
+ unless actors
140
+ type = options[:type]
141
+ count = options[:count]
142
+ raise ArgumentError, "Either :actors or :type and :count must be specified" unless type && count
143
+ actors = (0...count).map { actor_of(type) }
144
+ end
145
+ actors.each { |a| a.start }
146
+ actor_list = Arrays.as_list(actors.to_java)
147
+ actor_seq = Akka::Routing::CyclicIterator.new(actor_list)
148
+ actor_factory = proc { actor_seq }.to_function
149
+ Akka::Routing::Routing.load_balancer_actor(actor_factory)
150
+ end
151
+ end
152
+
153
+ module Akka
154
+ module Actor
155
+ module ActorRef
156
+ def <<(message)
157
+ send_one_way(message, Mikka.current_actor)
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module Mikka
4
+ VERSION = '1.0.0'
5
+ end
data/mikka.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../lib', __FILE__)
4
+
5
+ require 'mikka/version'
6
+
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'mikka'
10
+ s.version = Mikka::VERSION
11
+ s.platform = Gem::Platform::CURRENT
12
+ s.authors = ['Theo Hultberg']
13
+ s.email = ['theo@iconara.net']
14
+ s.homepage = 'http://github.com/iconara/mikka'
15
+ s.summary = %q{Mikka is a JRuby wrapper for Akka}
16
+ s.description = %q{Mikka adapts Akka's Java API to fit better with Ruby}
17
+
18
+ s.rubyforge_project = 'mikka'
19
+
20
+ s.add_dependency 'akka-actor-jars', '~> 1.1.0'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ # s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = %w(lib)
26
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mikka
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: universal-darwin-11
11
+ authors:
12
+ - Theo Hultberg
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-07 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: akka-actor-jars
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 1
30
+ - 0
31
+ version: 1.1.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Mikka adapts Akka's Java API to fit better with Ruby
35
+ email:
36
+ - theo@iconara.net
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - .gitignore
45
+ - .rvmrc
46
+ - Gemfile
47
+ - README.mdown
48
+ - Rakefile
49
+ - examples/hello_world.rb
50
+ - examples/load_balancing1.rb
51
+ - examples/load_balancing2.rb
52
+ - examples/proc_example.rb
53
+ - examples/simple_example.rb
54
+ - examples/supervision1.rb
55
+ - lib/akka.rb
56
+ - lib/mikka.rb
57
+ - lib/mikka/version.rb
58
+ - mikka.gemspec
59
+ has_rdoc: true
60
+ homepage: http://github.com/iconara/mikka
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirements: []
83
+
84
+ rubyforge_project: mikka
85
+ rubygems_version: 1.3.6
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Mikka is a JRuby wrapper for Akka
89
+ test_files: []
90
+