functional-ruby 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -126
  3. data/lib/functional.rb +4 -1
  4. data/lib/functional/utilities.rb +46 -0
  5. data/lib/functional/version.rb +1 -1
  6. data/lib/functional_ruby.rb +1 -1
  7. data/md/utilities.md +2 -0
  8. data/spec/functional/behavior_spec.rb +2 -2
  9. data/spec/functional/pattern_matching_spec.rb +2 -2
  10. data/spec/functional/utilities_spec.rb +131 -43
  11. data/spec/spec_helper.rb +1 -3
  12. metadata +3 -40
  13. data/lib/functional/agent.rb +0 -130
  14. data/lib/functional/all.rb +0 -13
  15. data/lib/functional/cached_thread_pool.rb +0 -122
  16. data/lib/functional/concurrency.rb +0 -35
  17. data/lib/functional/core.rb +0 -2
  18. data/lib/functional/event.rb +0 -53
  19. data/lib/functional/event_machine_defer_proxy.rb +0 -23
  20. data/lib/functional/fixed_thread_pool.rb +0 -89
  21. data/lib/functional/future.rb +0 -42
  22. data/lib/functional/global_thread_pool.rb +0 -3
  23. data/lib/functional/obligation.rb +0 -121
  24. data/lib/functional/promise.rb +0 -194
  25. data/lib/functional/thread_pool.rb +0 -61
  26. data/md/concurrency.md +0 -465
  27. data/md/future.md +0 -32
  28. data/md/obligation.md +0 -32
  29. data/md/promise.md +0 -220
  30. data/spec/functional/agent_spec.rb +0 -405
  31. data/spec/functional/cached_thread_pool_spec.rb +0 -112
  32. data/spec/functional/concurrency_spec.rb +0 -55
  33. data/spec/functional/event_machine_defer_proxy_spec.rb +0 -246
  34. data/spec/functional/event_spec.rb +0 -114
  35. data/spec/functional/fixed_thread_pool_spec.rb +0 -84
  36. data/spec/functional/future_spec.rb +0 -115
  37. data/spec/functional/obligation_shared.rb +0 -121
  38. data/spec/functional/promise_spec.rb +0 -310
  39. data/spec/functional/thread_pool_shared.rb +0 -209
@@ -1,6 +1,4 @@
1
- require 'eventmachine'
2
-
3
- require 'functional/all'
1
+ require 'functional'
4
2
 
5
3
  # import all the support files
6
4
  Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require File.expand_path(f) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functional-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-22 00:00:00.000000000 Z
11
+ date: 2013-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  description: |2
28
- A gem for adding Erlang, Clojure, and Go inspired concurrency and functional programming tools to Ruby.
28
+ A gem for adding Erlang, Clojure, and Go inspired functional programming tools to Ruby.
29
29
  email: jerry.dantonio@gmail.com
30
30
  executables: []
31
31
  extensions: []
@@ -35,46 +35,19 @@ extra_rdoc_files:
35
35
  files:
36
36
  - README.md
37
37
  - LICENSE
38
- - lib/functional/agent.rb
39
- - lib/functional/all.rb
40
38
  - lib/functional/behavior.rb
41
39
  - lib/functional/behaviour.rb
42
- - lib/functional/cached_thread_pool.rb
43
- - lib/functional/concurrency.rb
44
- - lib/functional/core.rb
45
- - lib/functional/event.rb
46
- - lib/functional/event_machine_defer_proxy.rb
47
- - lib/functional/fixed_thread_pool.rb
48
- - lib/functional/future.rb
49
- - lib/functional/global_thread_pool.rb
50
- - lib/functional/obligation.rb
51
40
  - lib/functional/pattern_matching.rb
52
- - lib/functional/promise.rb
53
- - lib/functional/thread_pool.rb
54
41
  - lib/functional/utilities.rb
55
42
  - lib/functional/version.rb
56
43
  - lib/functional.rb
57
44
  - lib/functional_ruby.rb
58
45
  - md/behavior.md
59
- - md/concurrency.md
60
- - md/future.md
61
- - md/obligation.md
62
46
  - md/pattern_matching.md
63
- - md/promise.md
64
47
  - md/utilities.md
65
- - spec/functional/agent_spec.rb
66
48
  - spec/functional/behavior_spec.rb
67
- - spec/functional/cached_thread_pool_spec.rb
68
- - spec/functional/concurrency_spec.rb
69
- - spec/functional/event_machine_defer_proxy_spec.rb
70
- - spec/functional/event_spec.rb
71
- - spec/functional/fixed_thread_pool_spec.rb
72
- - spec/functional/future_spec.rb
73
49
  - spec/functional/integration_spec.rb
74
- - spec/functional/obligation_shared.rb
75
50
  - spec/functional/pattern_matching_spec.rb
76
- - spec/functional/promise_spec.rb
77
- - spec/functional/thread_pool_shared.rb
78
51
  - spec/functional/utilities_spec.rb
79
52
  - spec/spec_helper.rb
80
53
  homepage: https://github.com/jdantonio/functional-ruby/
@@ -111,18 +84,8 @@ signing_key:
111
84
  specification_version: 4
112
85
  summary: Erlang and Clojure inspired functional programming tools for Ruby.
113
86
  test_files:
114
- - spec/functional/agent_spec.rb
115
87
  - spec/functional/behavior_spec.rb
116
- - spec/functional/cached_thread_pool_spec.rb
117
- - spec/functional/concurrency_spec.rb
118
- - spec/functional/event_machine_defer_proxy_spec.rb
119
- - spec/functional/event_spec.rb
120
- - spec/functional/fixed_thread_pool_spec.rb
121
- - spec/functional/future_spec.rb
122
88
  - spec/functional/integration_spec.rb
123
- - spec/functional/obligation_shared.rb
124
89
  - spec/functional/pattern_matching_spec.rb
125
- - spec/functional/promise_spec.rb
126
- - spec/functional/thread_pool_shared.rb
127
90
  - spec/functional/utilities_spec.rb
128
91
  - spec/spec_helper.rb
@@ -1,130 +0,0 @@
1
- require 'observer'
2
- require 'thread'
3
-
4
- require 'functional/global_thread_pool'
5
-
6
- module Functional
7
-
8
- # An agent is a single atomic value that represents an identity. The current value
9
- # of the agent can be requested at any time (#deref). Each agent has a work queue and operates on
10
- # the global thread pool. Consumers can #post code blocks to the agent. The code block (function)
11
- # will receive the current value of the agent as its sole parameter. The return value of the block
12
- # will become the new value of the agent. Agents support two error handling modes: fail and continue.
13
- # A good example of an agent is a shared incrementing counter, such as the score in a video game.
14
- class Agent
15
- include Observable
16
-
17
- TIMEOUT = 5
18
-
19
- attr_reader :initial
20
- attr_reader :timeout
21
-
22
- def initialize(initial, timeout = TIMEOUT)
23
- @value = initial
24
- @timeout = timeout
25
- @rescuers = []
26
- @validator = nil
27
- @queue = Queue.new
28
-
29
- $GLOBAL_THREAD_POOL << proc{ work }
30
- end
31
-
32
- def value(timeout = 0) return @value; end
33
- alias_method :deref, :value
34
-
35
- def rescue(clazz = Exception, &block)
36
- @rescuers << Rescuer.new(clazz, block) if block_given?
37
- return self
38
- end
39
- alias_method :catch, :rescue
40
- alias_method :on_error, :rescue
41
-
42
- def validate(&block)
43
- @validator = block if block_given?
44
- return self
45
- end
46
- alias_method :validates, :validate
47
- alias_method :validate_with, :validate
48
- alias_method :validates_with, :validate
49
-
50
- def post(&block)
51
- return @queue.length unless block_given?
52
- @queue << block
53
- return @queue.length
54
- end
55
-
56
- def <<(block)
57
- self.post(&block)
58
- return self
59
- end
60
-
61
- def length
62
- @queue.length
63
- end
64
- alias_method :size, :length
65
- alias_method :count, :length
66
-
67
- alias_method :add_watch, :add_observer
68
-
69
- private
70
-
71
- # @private
72
- Rescuer = Struct.new(:clazz, :block)
73
-
74
- # @private
75
- def try_rescue(ex) # :nodoc:
76
- rescuer = @rescuers.find{|r| ex.is_a?(r.clazz) }
77
- rescuer.block.call(ex) if rescuer
78
- rescue Exception => e
79
- # supress
80
- end
81
-
82
- # @private
83
- def work # :nodoc:
84
- loop do
85
- Thread.pass
86
- handler = @queue.pop
87
- begin
88
- result = Timeout.timeout(@timeout){
89
- handler.call(@value)
90
- }
91
- if @validator.nil? || @validator.call(result)
92
- @value = result
93
- changed
94
- notify_observers(Time.now, @value)
95
- end
96
- rescue Exception => ex
97
- try_rescue(ex)
98
- end
99
- end
100
- end
101
- end
102
- end
103
-
104
- module Kernel
105
-
106
- def agent(initial, timeout = Functional::Agent::TIMEOUT)
107
- return Functional::Agent.new(initial, timeout)
108
- end
109
- module_function :agent
110
-
111
- def deref(agent, timeout = nil)
112
- if agent.respond_to?(:deref)
113
- return agent.deref(timeout)
114
- elsif agent.respond_to?(:value)
115
- return agent.deref(timeout)
116
- else
117
- return nil
118
- end
119
- end
120
- module_function :deref
121
-
122
- def post(agent, &block)
123
- if agent.respond_to?(:post)
124
- return agent.post(&block)
125
- else
126
- return nil
127
- end
128
- end
129
- module_function :deref
130
- end
@@ -1,13 +0,0 @@
1
- require 'functional/agent'
2
- require 'functional/behavior'
3
- require 'functional/cached_thread_pool'
4
- require 'functional/concurrency'
5
- require 'functional/event'
6
- require 'functional/fixed_thread_pool'
7
- require 'functional/future'
8
- require 'functional/obligation'
9
- require 'functional/pattern_matching'
10
- require 'functional/promise'
11
- require 'functional/thread_pool'
12
- require 'functional/utilities'
13
- require 'functional/version'
@@ -1,122 +0,0 @@
1
- require 'thread'
2
-
3
- require 'functional/thread_pool'
4
- require 'functional/utilities'
5
-
6
- module Functional
7
-
8
- def self.new_cached_thread_pool
9
- return CachedThreadPool.new
10
- end
11
-
12
- class CachedThreadPool < ThreadPool
13
- behavior(:thread_pool)
14
-
15
- DEFAULT_GC_INTERVAL = 60
16
- DEFAULT_THREAD_IDLETIME = 60
17
-
18
- attr_reader :working
19
-
20
- def initialize(opts = {})
21
- @gc_interval = opts[:gc_interval] || DEFAULT_GC_INTERVAL
22
- @thread_idletime = opts[:thread_idletime] || DEFAULT_THREAD_IDLETIME
23
- super()
24
- @working = 0
25
- @mutex = Mutex.new
26
- end
27
-
28
- def kill
29
- @status = :killed
30
- @mutex.synchronize do
31
- @pool.each{|t| Thread.kill(t.thread) }
32
- end
33
- end
34
-
35
- def size
36
- return @pool.length
37
- end
38
-
39
- def post(*args, &block)
40
- raise ArgumentError.new('no block given') unless block_given?
41
- if running?
42
- collect_garbage if @pool.empty?
43
- @mutex.synchronize do
44
- if @working >= @pool.length
45
- create_worker_thread
46
- end
47
- @queue << [args, block]
48
- end
49
- return true
50
- else
51
- return false
52
- end
53
- end
54
-
55
- # @private
56
- def status # :nodoc:
57
- @mutex.synchronize do
58
- @pool.collect do |worker|
59
- [
60
- worker.status,
61
- worker.status == :idle ? delta(worker.idletime, timestamp) : nil,
62
- worker.thread.status
63
- ]
64
- end
65
- end
66
- end
67
-
68
- private
69
-
70
- Worker = Struct.new(:status, :idletime, :thread)
71
-
72
- # @private
73
- def create_worker_thread # :nodoc:
74
- worker = Worker.new(:idle, timestamp, nil)
75
-
76
- worker.thread = Thread.new(worker) do |me|
77
-
78
- loop do
79
- task = @queue.pop
80
-
81
- @working += 1
82
- me.status = :working
83
-
84
- if task == :stop
85
- me.status = :stopping
86
- break
87
- else
88
- task.last.call(*task.first)
89
- @working -= 1
90
- me.status = :idle
91
- me.idletime = timestamp
92
- end
93
- end
94
-
95
- @pool.delete(me)
96
- if @pool.empty?
97
- @termination.set
98
- @status = :shutdown unless killed?
99
- end
100
- end
101
-
102
- @pool << worker
103
- end
104
-
105
- # @private
106
- def collect_garbage # :nodoc:
107
- @collector = Thread.new do
108
- loop do
109
- sleep(@gc_interval)
110
- @mutex.synchronize do
111
- @pool.reject! do |worker|
112
- worker.thread.status.nil? ||
113
- (worker.status == :idle && @thread_idletime >= delta(worker.idletime, timestamp))
114
- end
115
- end
116
- @working = @pool.count{|worker| worker.status == :working}
117
- break if @pool.empty?
118
- end
119
- end
120
- end
121
- end
122
- end
@@ -1,35 +0,0 @@
1
- require 'thread'
2
-
3
- require 'functional/agent'
4
- require 'functional/future'
5
- require 'functional/promise'
6
-
7
- require 'functional/thread_pool'
8
- require 'functional/cached_thread_pool'
9
- require 'functional/fixed_thread_pool'
10
-
11
- require 'functional/global_thread_pool'
12
-
13
- require 'functional/event_machine_defer_proxy' if defined?(EventMachine)
14
-
15
- module Kernel
16
-
17
- # Post the given agruments and block to the Global Thread Pool.
18
- #
19
- # @param args [Array] zero or more arguments for the block
20
- # @param block [Proc] operation to be performed concurrently
21
- #
22
- # @return [true,false] success/failre of thread creation
23
- #
24
- # @note Althought based on Go's goroutines and Erlang's spawn/1,
25
- # Ruby has a vastly different runtime. Threads aren't nearly as
26
- # efficient in Ruby. Use this function appropriately.
27
- #
28
- # @see http://golang.org/doc/effective_go.html#goroutines
29
- # @see https://gobyexample.com/goroutines
30
- def go(*args, &block)
31
- return false unless block_given?
32
- $GLOBAL_THREAD_POOL.post(*args, &block)
33
- end
34
- module_function :go
35
- end
@@ -1,2 +0,0 @@
1
- require 'functional/behavior'
2
- require 'functional/pattern_matching'
@@ -1,53 +0,0 @@
1
- require 'thread'
2
- require 'timeout'
3
-
4
- module Functional
5
-
6
- class Event
7
-
8
- def initialize
9
- @set = false
10
- @notifier = Queue.new
11
- @mutex = Mutex.new
12
- @waiting = 0
13
- end
14
-
15
- def set?
16
- return @set == true
17
- end
18
-
19
- def set
20
- return true if set?
21
- @mutex.synchronize {
22
- @set = true
23
- while @waiting > 0
24
- @notifier << :set
25
- @waiting -= 1
26
- end
27
- }
28
- end
29
-
30
- def reset
31
- @mutex.synchronize {
32
- @set = false
33
- }
34
- end
35
-
36
- def wait(timeout = nil)
37
- return true if set?
38
-
39
- if timeout.nil?
40
- @waiting += 1
41
- @notifier.pop
42
- else
43
- Timeout::timeout(timeout) do
44
- @waiting += 1
45
- @notifier.pop
46
- end
47
- end
48
- return true
49
- rescue Timeout::Error
50
- return false
51
- end
52
- end
53
- end