spnet 0.1.4 → 0.1.5

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