spnet 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/README.rdoc +6 -3
  2. data/lib/spnet.rb +23 -5
  3. data/lib/spnet/core/block.rb +46 -0
  4. data/lib/spnet/core/in_port.rb +41 -0
  5. data/lib/spnet/core/limiter.rb +30 -0
  6. data/lib/spnet/core/link.rb +70 -0
  7. data/lib/spnet/core/network.rb +54 -0
  8. data/lib/spnet/core/out_port.rb +41 -0
  9. data/lib/spnet/limiters/enum_limiter.rb +24 -0
  10. data/lib/spnet/limiters/lower_limiter.rb +31 -0
  11. data/lib/spnet/limiters/no_limiter.rb +11 -0
  12. data/lib/spnet/limiters/range_limiter.rb +24 -0
  13. data/lib/spnet/limiters/upper_limiter.rb +31 -0
  14. data/lib/spnet/ports/command_in_port.rb +16 -8
  15. data/lib/spnet/ports/command_out_port.rb +17 -11
  16. data/lib/spnet/ports/param_in_port.rb +42 -0
  17. data/lib/spnet/ports/param_out_port.rb +32 -0
  18. data/lib/spnet/ports/signal_in_port.rb +20 -15
  19. data/lib/spnet/ports/signal_out_port.rb +12 -7
  20. data/lib/spnet/storage/block_state.rb +41 -0
  21. data/lib/spnet/storage/link_state.rb +38 -0
  22. data/lib/spnet/storage/network_state.rb +44 -0
  23. data/lib/spnet/storage/port_locater.rb +21 -0
  24. data/lib/spnet/version.rb +2 -1
  25. data/spec/core/block_spec.rb +80 -0
  26. data/spec/core/in_port_spec.rb +46 -0
  27. data/spec/core/limiter_spec.rb +7 -0
  28. data/spec/core/link_spec.rb +103 -0
  29. data/spec/core/network_spec.rb +40 -0
  30. data/spec/core/out_port_spec.rb +46 -0
  31. data/spec/limiters/enum_limiter_spec.rb +28 -0
  32. data/spec/limiters/lower_limiter_spec.rb +48 -0
  33. data/spec/limiters/no_limiter_spec.rb +12 -0
  34. data/spec/limiters/range_limiter_spec.rb +121 -0
  35. data/spec/limiters/upper_limiter_spec.rb +47 -0
  36. data/spec/ports/command_out_port_spec.rb +8 -15
  37. data/spec/ports/{value_in_port_spec.rb → param_in_port_spec.rb} +2 -2
  38. data/spec/ports/param_out_port_spec.rb +34 -0
  39. data/spec/ports/signal_in_port_spec.rb +2 -1
  40. data/spec/ports/signal_out_port_spec.rb +6 -37
  41. data/spec/spec_helper.rb +43 -0
  42. data/spec/storage/block_state_spec.rb +40 -0
  43. data/spec/storage/link_state_spec.rb +28 -0
  44. data/spec/storage/network_state_spec.rb +42 -0
  45. data/spec/storage/port_locater_spec.rb +11 -0
  46. data/spnet.gemspec +0 -1
  47. metadata +55 -35
  48. data/lib/spnet/block.rb +0 -40
  49. data/lib/spnet/in_port.rb +0 -29
  50. data/lib/spnet/out_port.rb +0 -64
  51. data/lib/spnet/ports/value_in_port.rb +0 -27
  52. data/lib/spnet/ports/value_out_port.rb +0 -28
  53. data/spec/block_spec.rb +0 -38
  54. data/spec/in_port_spec.rb +0 -29
  55. data/spec/out_port_spec.rb +0 -46
  56. data/spec/ports/value_out_port_spec.rb +0 -41
@@ -1,8 +1,9 @@
1
1
  = spnet
2
2
 
3
3
  * {Homepage}[https://rubygems.org/gems/spnet]
4
+ * {Source Code}[https://github.com/jamestunnell/spnet]
4
5
  * {Documentation}[http://rubydoc.info/gems/spnet/frames]
5
- * {Email}[mailto:jamestunnell at lavabit.com]
6
+ * {Email}[mailto:jamestunnell@lavabit.com]
6
7
 
7
8
  == Description
8
9
 
@@ -12,9 +13,11 @@ Provide infrastructure for forming processing networks.
12
13
 
13
14
  Signal ports: Used to pass a stream of data through a block.
14
15
 
15
- Value ports: Used to get/set a value within a block (usually to control a parameter), with optional range limiting.
16
+ Param ports: Used to get/set a value within a block (usually to control a parameter).
16
17
 
17
- Command ports: Used to trigger the execution a command within a block, with optional data as well.
18
+ Command ports: Used to trigger the execution a command within a block, with optional data.
19
+
20
+ Limiters: Control the limits on values that can be sent into signal or param ports.
18
21
 
19
22
  == Examples
20
23
 
@@ -1,11 +1,29 @@
1
+ require 'hashmake'
2
+
1
3
  require 'spnet/version'
2
- require 'spnet/in_port'
3
- require 'spnet/out_port'
4
- require 'spnet/block'
4
+
5
+ require 'spnet/core/in_port'
6
+ require 'spnet/core/out_port'
7
+ require 'spnet/core/limiter'
8
+
9
+ require 'spnet/limiters/no_limiter'
10
+ require 'spnet/limiters/lower_limiter'
11
+ require 'spnet/limiters/upper_limiter'
12
+ require 'spnet/limiters/range_limiter'
13
+ require 'spnet/limiters/enum_limiter'
5
14
 
6
15
  require 'spnet/ports/signal_in_port'
7
16
  require 'spnet/ports/signal_out_port'
8
- require 'spnet/ports/value_in_port'
9
- require 'spnet/ports/value_out_port'
17
+ require 'spnet/ports/param_in_port'
18
+ require 'spnet/ports/param_out_port'
10
19
  require 'spnet/ports/command_in_port'
11
20
  require 'spnet/ports/command_out_port'
21
+
22
+ require 'spnet/core/block'
23
+ require 'spnet/core/link'
24
+ require 'spnet/core/network'
25
+
26
+ require 'spnet/storage/port_locater.rb'
27
+ require 'spnet/storage/link_state.rb'
28
+ require 'spnet/storage/block_state.rb'
29
+ require 'spnet/storage/network_state.rb'
@@ -0,0 +1,46 @@
1
+ module SPNet
2
+
3
+ # Base class for encapsulating processing functionality. Connects to
4
+ # other blocks via input and output ports.
5
+ #
6
+ # @author James Tunnell
7
+ class Block
8
+ include Hashmake::HashMakeable
9
+
10
+ attr_reader :in_ports, :out_ports, :sample_rate
11
+
12
+ # Define ArgSpec's to use in processing hashed arguments during #initialize.
13
+ ARG_SPECS = {
14
+ :sample_rate => arg_spec(:reqd => true, :type => Numeric, :validator => ->(a){ a > 0 }),
15
+ :algorithm => arg_spec(:reqd => true, :type => Proc, :validator => ->(p){ p.arity == 1 }),
16
+ :in_ports => arg_spec_hash(:reqd => false, :type => InPort),
17
+ :out_ports => arg_spec_hash(:reqd => false, :type => OutPort),
18
+ }
19
+
20
+ # A new instance of Block.
21
+ # @param [Hash] args Hashed arguments for initialization. See Block::ARG_SPECS
22
+ # for details of which keys are required.
23
+ def initialize args = {}
24
+ hash_make Block::ARG_SPECS, args
25
+ end
26
+
27
+ # Execute the block algorithm.
28
+ # @param [Fixnum] count The number of steps to execute. Passed on to the algorithm Proc.
29
+ def step count
30
+ @algorithm.call count
31
+ end
32
+
33
+ # Produces a BlockState object based on this Block object.
34
+ # @return [BlockState]
35
+ def export_state
36
+ port_params = {}
37
+ @in_ports.each do |name, port|
38
+ if port.is_a?(ParamInPort)
39
+ port_params[name] = port.get_value
40
+ end
41
+ end
42
+
43
+ BlockState.new(:class_sym => self.class.to_s.to_sym, :port_params => port_params)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ module SPNet
2
+
3
+ # A port that exposes some functionality in a block.
4
+ #
5
+ # @author James Tunnell
6
+ class InPort
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define ArgSpec's to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :matching_class => arg_spec(:reqd => true, :type => Class),
12
+ }
13
+
14
+ attr_reader :link, :matching_class
15
+
16
+ # A new instance of InPort.
17
+ # @param [Hash] args Hashed arguments for initialization. See InPort::ARG_SPECS
18
+ # for details.
19
+ def initialize args
20
+ hash_make InPort::ARG_SPECS, args
21
+ @link = nil
22
+ end
23
+
24
+ # Set @link to the given Link object.
25
+ def set_link link
26
+ raise ArgumentError, "link 'to' port is not self" unless link.to == self
27
+ @link = link
28
+ end
29
+
30
+ # Set @link to nil.
31
+ def clear_link
32
+ @link = nil
33
+ end
34
+
35
+ # Return true if @link is not nil.
36
+ def linked?
37
+ !link.nil?
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,30 @@
1
+ module SPNet
2
+
3
+ # Defines a limit, where a value should not be above (for upper limit) or below
4
+ # (for lower limit). If inclusive is set to true, the limit indicates that values
5
+ # at the limit are OK.
6
+ #
7
+ # @author James Tunnell
8
+ class Limit
9
+ attr_reader :value, :inclusive
10
+
11
+ def inclusive?
12
+ return @inclusive
13
+ end
14
+
15
+ def initialize value, inclusive
16
+ @value = value
17
+ @inclusive = inclusive
18
+ end
19
+ end
20
+
21
+ # Base class for limiting values. Does nothing on it's own.
22
+ #
23
+ # @author James Tunnell
24
+ class Limiter
25
+ def apply_limit value, current_value
26
+ raise NotImplementedError
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,70 @@
1
+ module SPNet
2
+
3
+ # Form a connection between an OutPort and an InPort.
4
+ #
5
+ # @author James Tunnell
6
+ class Link
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define arg specs to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :from => arg_spec(:reqd => true, :type => OutPort),
12
+ :to => arg_spec(:reqd => true, :type => InPort)
13
+ }
14
+
15
+ attr_reader :to, :from
16
+
17
+ # A new instance of Link. Link is not active by default (does not set
18
+ # from.link and to.link to self).
19
+ # @param [Hash] args Hashed arguments for initialization. See Link::ARG_SPECS
20
+ # for details of which keys are required.
21
+ def initialize args = {}
22
+ hash_make Link::ARG_SPECS, args
23
+
24
+ raise ArgumentError, "from port class #{@from.class} is not a #{@to.matching_class}" unless @from.is_a?(@to.matching_class)
25
+ raise ArgumentError, "to port class #{@to.class} is not a #{@from.matching_class}" unless @to.is_a?(@from.matching_class)
26
+ end
27
+
28
+ # Make the link active by setting from.link and to.link to self.
29
+ def activate
30
+ @from.set_link self
31
+ @to.set_link self
32
+ end
33
+
34
+ # Make the link inactive by setting from.link and to.link to nil.
35
+ def deactivate
36
+ @from.clear_link
37
+ @to.clear_link
38
+ end
39
+
40
+ # Return true if the link is active (from.link and to.link are set to to self).
41
+ def active?
42
+ (@from.link == self) && (@to.link == self)
43
+ end
44
+
45
+ # Produce a LinkState object from the current Link object.
46
+ def export_state blocks
47
+ from, to = nil, nil
48
+
49
+ blocks.each do |block_name, block|
50
+ block.out_ports.each do |port_name, port|
51
+ if port == @from
52
+ from = PortLocater.new(:block_name => block_name, :port_name => port_name)
53
+ break
54
+ end
55
+ end
56
+
57
+ block.in_ports.each do |port_name, port|
58
+ if port == @to
59
+ to = PortLocater.new(:block_name => block_name, :port_name => port_name)
60
+ break
61
+ end
62
+ end
63
+ end
64
+
65
+ raise "could not find from port" if from.nil?
66
+ raise "could not find to port" if to.nil?
67
+ return LinkState.new(:from => from, :to => to)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,54 @@
1
+ module SPNet
2
+
3
+ # A signal processing network, formed by connecting Block objects with Link objects.
4
+ #
5
+ # @author James Tunnell
6
+ class Network
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define arg specs to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :sample_rate => arg_spec(:reqd => true, :type => Numeric, :validator => ->(a){a > 0.0}),
12
+ :name => arg_spec(:reqd => false, :type => String, :default => ""),
13
+ :blocks => arg_spec_hash(:reqd => false, :type => Block),
14
+ :links => arg_spec_array(:reqd => false, :type => Link),
15
+ }
16
+
17
+ attr_reader :sample_rate, :name, :blocks, :links
18
+
19
+ # A new instance of Network. Changes all block sample rates (if necessary) to
20
+ # match the given sample rate. Activates links.
21
+ # @param [Hash] args Hashed arguments for initialization. See Network::ARG_SPECS
22
+ # for details of which keys are required.
23
+ def initialize args = {}
24
+ hash_make Network::ARG_SPECS, args
25
+
26
+ # ensure that all sample rates match given rate
27
+ @blocks.each do |block_name, block|
28
+ if block.sample_rate != @sample_rate
29
+ raise ArgumentError, "block sample rate #{block.sample_rate} does not match network sample rate #{@sample_rate}"
30
+ end
31
+ end
32
+
33
+ @links.each do |link|
34
+ link.activate
35
+ end
36
+ end
37
+
38
+ # Produce a NetworkState object from the current Network object.
39
+ def export_state
40
+ block_states = {}
41
+ @blocks.each do |block_name, block|
42
+ block_states[block_name] = block.export_state
43
+ end
44
+
45
+ link_states = []
46
+ @links.each do |link|
47
+ link_states.push link.export_state(@blocks)
48
+ end
49
+
50
+ return NetworkState.new(:name => @name, :block_states => block_states, :link_states => link_states)
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module SPNet
2
+
3
+ # A port that is used to exercise some functionality exposed by an InPort.
4
+ #
5
+ # @author James Tunnell
6
+ class OutPort
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define ArgSpec's to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :matching_class => arg_spec(:reqd => true, :type => Class),
12
+ }
13
+
14
+ attr_reader :name, :link, :matching_class
15
+
16
+ # A new instance of OutPort.
17
+ # @param [Hash] args Hashed arguments for initialization. See OutPort::ARG_SPECS
18
+ # for details.
19
+ def initialize args
20
+ hash_make OutPort::ARG_SPECS, args
21
+ @link = nil
22
+ end
23
+
24
+ # Set @link to the given Link object.
25
+ def set_link link
26
+ raise ArgumentError, "link 'from' port is not self" unless link.from == self
27
+ @link = link
28
+ end
29
+
30
+ # Set @link to nil.
31
+ def clear_link
32
+ @link = nil
33
+ end
34
+
35
+ # Return true if @link is not nil.
36
+ def linked?
37
+ !link.nil?
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,24 @@
1
+ module SPNet
2
+ # Keeps values to those found in the given Enumerable object.
3
+ #
4
+ # @author James Tunnell
5
+ class EnumLimiter < Limiter
6
+ attr_reader :values
7
+
8
+ def initialize values
9
+ raise ArgumentError, "values is not an Enumerable" unless values.is_a?(Enumerable)
10
+ @values = values
11
+ end
12
+
13
+ # Limit the given value to those given by @values. If the given value is not
14
+ # found, return the current value.
15
+ def apply_limit value, current_value
16
+ if @values.include? value
17
+ return value
18
+ else
19
+ return current_value
20
+ end
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,31 @@
1
+ module SPNet
2
+ # Keeps values at or above the given Limit.
3
+ #
4
+ # @author James Tunnell
5
+ class LowerLimiter < Limiter
6
+ attr_reader :limit, :inclusive
7
+
8
+ def initialize limit, inclusive
9
+ @limit = limit
10
+ @inclusive = inclusive
11
+ end
12
+
13
+ # Limit the given value to be at or above @limit. Ignores the current_value parameter.
14
+ def apply_limit value, current_value = nil
15
+ if inclusive
16
+ if value >= @limit
17
+ return value
18
+ else
19
+ return @limit
20
+ end
21
+ else
22
+ if value > @limit
23
+ return value
24
+ else
25
+ return @limit + Float::EPSILON
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,11 @@
1
+ module SPNet
2
+ # Does not limit values at all.
3
+ #
4
+ # @author James Tunnell
5
+ class NoLimiter < Limiter
6
+ # Does not limit at all. Return the given value.
7
+ def apply_limit value, current_value = nil
8
+ return value
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module SPNet
2
+ # Keeps values between the given Limit objects.
3
+ #
4
+ # @author James Tunnell
5
+ class RangeLimiter < Limiter
6
+ attr_reader :lower, :upper
7
+
8
+ def initialize lower_limit, lower_inclusive, upper_limit, upper_inclusive
9
+ @lower = LowerLimiter.new(lower_limit, lower_inclusive)
10
+ @upper = UpperLimiter.new(upper_limit, upper_inclusive)
11
+ end
12
+
13
+ # Limit the given value to be between lower and upper limits. Ignores the current_value parameter.
14
+ def apply_limit value, current_value = nil
15
+ new_value = @lower.apply_limit value
16
+ if(new_value == value)
17
+ # value is OK so far. Make sure the right (upper) limit is OK too.
18
+ new_value = @upper.apply_limit value
19
+ end
20
+ return new_value
21
+ end
22
+ end
23
+
24
+ end