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
@@ -0,0 +1,31 @@
1
+ module SPNet
2
+ # Keeps values at or below the given Limit.
3
+ #
4
+ # @author James Tunnell
5
+ class UpperLimiter < 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 below @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
@@ -1,25 +1,33 @@
1
- require 'hashmake'
2
-
3
1
  module SPNet
2
+
3
+ # Provides a means to list and execute commands in a Block object.
4
+ #
5
+ # @author James Tunnell
4
6
  class CommandInPort < InPort
5
7
 
6
8
  include Hashmake::HashMakeable
7
9
 
8
- ARG_SPECS = [
9
- Hashmake::ArgSpec.new(:key => :command_map, :reqd => true, :type => Proc, :container => Hashmake::ArgSpec::CONTAINER_HASH),
10
- ]
10
+ # Define arg specs to use in processing hashed arguments during #initialize.
11
+ ARG_SPECS = {
12
+ :command_map => arg_spec_hash(:reqd => true, :type => Proc, :validator => ->(a){a.arity == 1}),
13
+ }
11
14
 
15
+ # A new instance of CommandInPort.
16
+ # @param [Hash] hashed_args Hashed arguments for initialization. See Network::ARG_SPECS
17
+ # for details.
12
18
  def initialize hashed_args
13
- hash_make(CommandInPort::ARG_SPECS, hashed_args)
14
- hashed_args.merge!(:matching_port_class => CommandOutPort)
15
- super(hashed_args)
19
+ hash_make CommandInPort::ARG_SPECS, hashed_args
20
+ super(:matching_class => CommandOutPort)
16
21
  end
17
22
 
23
+ # List the commands that are available.
18
24
  def list_commands
19
25
  @command_map.keys
20
26
  end
21
27
 
28
+ # Execute a command with the given data (nil by default).
22
29
  def exec_command command, data
30
+ raise "Command #{command} not found in command list" unless @command_map.has_key?(command)
23
31
  @command_map[command].call data
24
32
  end
25
33
  end
@@ -1,25 +1,31 @@
1
1
  module SPNet
2
+
3
+ # Execute commands for a connected CommandInPort object.
4
+ #
5
+ # @author James Tunnell
2
6
  class CommandOutPort < OutPort
3
7
 
4
- def initialize hashed_args = {}
5
- hashed_args.merge!(:matching_port_class => CommandInPort)
6
- super(hashed_args)
8
+ # A new instance of CommandOutPort.
9
+ def initialize
10
+ super(:matching_class => CommandInPort)
7
11
  end
8
12
 
13
+ # If linked, return the result of calling the connected CommandInPort object's
14
+ # list_commands method. Otherwise, return false.
9
15
  def list_commands
10
- rvs = []
11
- @links.each do |link|
12
- rvs.push link.list_commands
16
+ unless @link.nil?
17
+ return @link.to.list_commands
13
18
  end
14
- return rvs
19
+ return false
15
20
  end
16
21
 
22
+ # If linked, return the result of calling the connected CommandInPort object's
23
+ # exec_command method. Otherwise, return false.
17
24
  def exec_command command, data = nil
18
- rvs = []
19
- @links.each do |link|
20
- rvs.push link.exec_command(command, data)
25
+ unless @link.nil?
26
+ return @link.to.exec_command(command, data)
21
27
  end
22
- return rvs
28
+ return false
23
29
  end
24
30
 
25
31
  end
@@ -0,0 +1,42 @@
1
+ module SPNet
2
+
3
+ # Provides a means to get/set a parameter value in a Block object.
4
+ #
5
+ # @author James Tunnell
6
+ class ParamInPort < InPort
7
+
8
+ include Hashmake::HashMakeable
9
+
10
+ # Define arg specs to use in processing hashed arguments during #initialize.
11
+ ARG_SPECS = {
12
+ :limiter => arg_spec(:reqd => false, :type => Limiter, :default => ->(){ NoLimiter.new } ),
13
+ :get_value_handler => arg_spec(:reqd => true, :type => Proc, :validator => ->(p){ p.arity == 0 }),
14
+ :set_value_handler => arg_spec(:reqd => true, :type => Proc, :validator => ->(p){ p.arity == 1 })
15
+ }
16
+
17
+ attr_reader :limiter
18
+
19
+ # A new instance of ParamInPort.
20
+ # @param [Hash] hashed_args Hashed arguments for initialization. See Network::ARG_SPECS
21
+ # for details.
22
+ def initialize hashed_args = {}
23
+ hash_make ParamInPort::ARG_SPECS, hashed_args
24
+ @skip_limiting = @limiter.is_a?(NoLimiter)
25
+
26
+ super(:matching_class => ParamOutPort)
27
+ end
28
+
29
+ # Set the parameter to the given value.
30
+ def set_value value
31
+ unless @skip_limiting
32
+ value = @limiter.apply_limit value, get_value
33
+ end
34
+ @set_value_handler.call value
35
+ end
36
+
37
+ # Get the parameter's current value.
38
+ def get_value
39
+ @get_value_handler.call
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ module SPNet
2
+
3
+ # Output value to a connected ParamInPort object.
4
+ #
5
+ # @author James Tunnell
6
+ class ParamOutPort < OutPort
7
+
8
+ # A new instance of ParamOutPort.
9
+ def initialize
10
+ super(:matching_class => ParamInPort)
11
+ end
12
+
13
+ # If linked, return the result of calling the connected ParamInPort object's
14
+ # set_value method. Otherwise, return false.
15
+ def set_value value
16
+ if linked?
17
+ return @link.to.set_value value
18
+ end
19
+ return false
20
+ end
21
+
22
+ # If linked, return the result of calling the connected ParamInPort object's
23
+ # get_value method. Otherwise, return false.
24
+ def get_value
25
+ if linked?
26
+ return @link.to.get_value
27
+ end
28
+ return false
29
+ end
30
+
31
+ end
32
+ end
@@ -1,39 +1,44 @@
1
- require 'hashmake'
2
- require 'spcore'
3
-
4
1
  module SPNet
2
+
3
+ # Recieves signal input for processing in a Block object.
4
+ #
5
+ # @author James Tunnell
5
6
  class SignalInPort < InPort
6
7
 
7
8
  include Hashmake::HashMakeable
8
9
 
9
- DEFAULT_LIMITS = (-Float::MAX..Float::MAX)
10
+ # Define arg specs to use in processing hashed arguments during #initialize.
11
+ ARG_SPECS = {
12
+ :limiter => arg_spec(:reqd => false, :type => Limiter, :default => ->(){ NoLimiter.new }, :validator => ->(a){ !a.is_a?(EnumLimiter) }),
13
+ }
10
14
 
11
- ARG_SPECS = [
12
- Hashmake::ArgSpec.new(:reqd => false, :key => :limits, :type => Range, :default => DEFAULT_LIMITS)
13
- ]
14
-
15
- attr_reader :limits, :queue
15
+ attr_reader :limiter, :queue
16
16
 
17
+ # A new instance of SignalInPort.
18
+ # @param [Hash] hashed_args Hashed arguments for initialization. See Network::ARG_SPECS
19
+ # for details.
17
20
  def initialize hashed_args = {}
18
- hash_make(SignalInPort::ARG_SPECS, hashed_args)
21
+ hash_make SignalInPort::ARG_SPECS, hashed_args
22
+
19
23
  @queue = []
20
- @skip_limiting = (@limits == DEFAULT_LIMITS)
21
- @limiter = SPCore::Limiters.make_range_limiter @limits
24
+ @skip_limiting = @limiter.is_a?(NoLimiter)
22
25
 
23
- hashed_args.merge!(:matching_port_class => SignalOutPort)
24
- super(hashed_args)
26
+ super(:matching_class => SignalOutPort)
25
27
  end
26
28
 
29
+ # Add values to queue.
27
30
  def enqueue_values values
28
31
  unless @skip_limiting
29
32
  for i in 0...values.count
30
- values[i] = @limiter.call(values[i])
33
+ values[i] = @limiter.apply_limit values[i]
31
34
  end
32
35
  end
33
36
 
34
37
  @queue.concat values
35
38
  end
36
39
 
40
+ # Remove values to queue.
41
+ # @param [Fixnum] count Number of values to remove.
37
42
  def dequeue_values count = @queue.count
38
43
  raise ArgumentError, "count is greater than @queue.count" if count > @queue.count
39
44
  @queue.slice!(0...count)
@@ -1,17 +1,22 @@
1
- require 'set'
2
-
3
1
  module SPNet
2
+
3
+ # Output signal values to a connected SignalInPort object.
4
+ #
5
+ # @author James Tunnell
4
6
  class SignalOutPort < OutPort
5
7
 
6
- def initialize hashed_args = {}
7
- hashed_args.merge!(:matching_port_class => SignalInPort)
8
- super(hashed_args)
8
+ # A new instance of SignalOutPort.
9
+ def initialize
10
+ super(:matching_class => SignalInPort)
9
11
  end
10
12
 
13
+ # If linked, return the result of calling the connected SignalInPort object's
14
+ # enqueue_values method. Otherwise, return false.
11
15
  def send_values values
12
- @links.each do |link|
13
- link.enqueue_values values
16
+ if linked?
17
+ @link.to.enqueue_values values
14
18
  end
19
+ return false
15
20
  end
16
21
 
17
22
  end
@@ -0,0 +1,41 @@
1
+ module SPNet
2
+
3
+ # Represent a Block object using only serializeable objects.
4
+ #
5
+ # @author James Tunnell
6
+ class BlockState
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define arg specs to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :class_sym => arg_spec(:reqd => true, :type => Symbol),
12
+ :port_params => arg_spec_hash(:reqd => false, :type => Object)
13
+ }
14
+
15
+ attr_reader :class_sym, :hashed_args, :port_params
16
+
17
+ # A new instance of NetworkState.
18
+ # @param [Hash] args Hashed arguments for initialization. See Network::ARG_SPECS
19
+ # for details of which keys are required.
20
+ def initialize args
21
+ hash_make BlockState::ARG_SPECS, args
22
+ end
23
+
24
+ # Produce a Block object from the current BlockState object.
25
+ def make_block args
26
+ raise ArgumentError, "args does not have :sample_rate key" unless args.has_key?(:sample_rate)
27
+
28
+ klass = Kernel.const_get(@class_sym)
29
+ block = klass.new :sample_rate => args[:sample_rate]
30
+
31
+ @port_params.each do |port_name,value|
32
+ if block.in_ports.has_key?(port_name)
33
+ port = block.in_ports[port_name]
34
+ port.set_value value
35
+ end
36
+ end
37
+
38
+ return block
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ module SPNet
2
+
3
+ # Represent a Link object using only serializeable objects.
4
+ #
5
+ # @author James Tunnell
6
+ class LinkState
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 => PortLocater),
12
+ :to => arg_spec(:reqd => true, :type => PortLocater)
13
+ }
14
+
15
+ attr_reader :from, :to
16
+
17
+ def initialize args
18
+ hash_make ARG_SPECS, args
19
+ end
20
+
21
+ # Make a Link objet from the current LinkState object.
22
+ def make_link blocks
23
+ raise "from block #{@from.block_name} not found" unless blocks.has_key?(@from.block_name)
24
+ raise "to block #{@to.block_name} not found" unless blocks.has_key?(@to.block_name)
25
+
26
+ from_block = blocks[@from.block_name]
27
+ to_block = blocks[@to.block_name]
28
+
29
+ raise "from port #{@from.port_name} not found" unless from_block.out_ports.has_key?(@from.port_name)
30
+ raise "to port #{@to.port_name} not found" unless to_block.in_ports.has_key?(@to.port_name)
31
+
32
+ from_port = from_block.out_ports[@from.port_name]
33
+ to_port = to_block.in_ports[@to.port_name]
34
+
35
+ return Link.new(:from => from_port, :to => to_port)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,44 @@
1
+ module SPNet
2
+
3
+ # Represents a Network object using only serializeable objects.
4
+ #
5
+ # @author James Tunnell
6
+ class NetworkState
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define arg specs to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :name => arg_spec(:reqd => false, :type => String, :default => ""),
12
+ :block_states => arg_spec_hash(:reqd => false, :type => BlockState),
13
+ :link_states => arg_spec_array(:reqd => false, :type => LinkState),
14
+ }
15
+
16
+ attr_reader :sample_rate, :name, :block_models, :link_models
17
+
18
+ # A new instance of NetworkState.
19
+ # @param [Hash] args Hashed arguments for initialization. See Network::ARG_SPECS
20
+ # for details of which keys are required.
21
+ def initialize args = {}
22
+ hash_make NetworkState::ARG_SPECS, args
23
+ end
24
+
25
+ # Produce a Network object from the current NetworkState object.
26
+ # @param [Hash] args Hashed arguments. The only key required is :sample_rate.
27
+ def make_network args
28
+ raise ArgumentError, "args does not have :sample_rate key" unless args.has_key?(:sample_rate)
29
+ sample_rate = args[:sample_rate]
30
+
31
+ blocks = {}
32
+ @block_states.each do |block_name, block_state|
33
+ blocks[block_name] = block_state.make_block :sample_rate => sample_rate
34
+ end
35
+
36
+ links = []
37
+ @link_states.each do |link_state|
38
+ links.push link_state.make_link blocks
39
+ end
40
+
41
+ Network.new :name => @name, :blocks => blocks, :links => links, :sample_rate => sample_rate
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ module SPNet
2
+
3
+ # Locate a port based on the block and port name, rather than an object reference.
4
+ #
5
+ # @author James Tunnell
6
+ class PortLocater
7
+ include Hashmake::HashMakeable
8
+
9
+ # Define arg specs to use in processing hashed arguments during #initialize.
10
+ ARG_SPECS = {
11
+ :block_name => arg_spec(:reqd => true, :type => String),
12
+ :port_name => arg_spec(:reqd => true, :type => String),
13
+ }
14
+
15
+ attr_reader :block_name, :port_name
16
+
17
+ def initialize args
18
+ hash_make ARG_SPECS, args
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,5 @@
1
+ # Provide infrastructure for forming processing networks.
1
2
  module SPNet
2
3
  # spnet version
3
- VERSION = "0.1.4"
4
+ VERSION = "0.1.5"
4
5
  end
@@ -0,0 +1,80 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe SPNet::Block do
4
+ before :all do
5
+ @sample_rate = 1.0
6
+ end
7
+
8
+ context '.new' do
9
+ context 'no I/O ports given' do
10
+ before :all do
11
+ @block = SPNet::Block.new :sample_rate => @sample_rate, :algorithm => ->(a){}
12
+ end
13
+
14
+ it 'should have no input ports' do
15
+ @block.in_ports.should be_empty
16
+ end
17
+
18
+ it 'should have no output ports' do
19
+ @block.out_ports.should be_empty
20
+ end
21
+ end
22
+
23
+ context '1 in and 1 out port given' do
24
+ before :all do
25
+ @block = SPNet::Block.new(
26
+ :sample_rate => @sample_rate, :algorithm => ->(a){},
27
+ :in_ports => { "IN" => SPNet::SignalInPort.new }, :out_ports => { "OUT" => SPNet::SignalOutPort.new },
28
+ )
29
+ end
30
+
31
+ it 'should have 1 input port' do
32
+ @block.in_ports.count.should be 1
33
+ @block.in_ports.has_key?("IN")
34
+ end
35
+
36
+ it 'should have 1 output port' do
37
+ @block.out_ports.count.should be 1
38
+ @block.out_ports.has_key?("OUT")
39
+ end
40
+ end
41
+ end
42
+
43
+ context '#sample_rate' do
44
+ it 'should return the given sample_rate' do
45
+ block = TestBlock.new :sample_rate => @sample_rate
46
+ block.sample_rate.should eq(@sample_rate)
47
+ end
48
+ end
49
+
50
+ context '#step' do
51
+ it 'should exercise the given algorithm, passing the count' do
52
+ block = TestBlock.new :sample_rate => @sample_rate
53
+ collector = SignalInPort.new
54
+ link = Link.new(:from => block.out_ports["OUT"], :to => collector)
55
+ link.activate
56
+ block.in_ports["IN"].enqueue_values [1,3,5]
57
+ block.step 1
58
+ collector.dequeue_values(1).should eq([1])
59
+ block.step 2
60
+ collector.dequeue_values(2).should eq([3,5])
61
+ end
62
+ end
63
+
64
+ context '#export_state' do
65
+ before :all do
66
+ block = TestBlock.new :sample_rate => @sample_rate
67
+ block.in_ports["VALUE1"].set_value(4.4)
68
+ block.in_ports["VALUE2"].set_value(5.5)
69
+ @state = block.export_state
70
+ end
71
+
72
+ it 'should set class_sym to :Block' do
73
+ @state.class_sym.should eq(:TestBlock)
74
+ end
75
+
76
+ it 'should set port_params according to ParamInPort settings' do
77
+ @state.port_params.should eq("VALUE1" => 4.4, "VALUE2" => 5.5)
78
+ end
79
+ end
80
+ end