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