functional-ruby 0.6.0 → 0.7.0

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.
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