diff --git a/lib/circuits/component/and.rb b/lib/circuits/component/and.rb index f1d5aea..58708aa 100644 --- a/lib/circuits/component/and.rb +++ b/lib/circuits/component/and.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical AND of the inputs def tick - outputs[0].set(inputs.map(&:get).inject(:&)) + self[:out].set(inputs.map(&:get).inject(:&)) end end end diff --git a/lib/circuits/component/base.rb b/lib/circuits/component/base.rb index 5f5b3da..51d796f 100644 --- a/lib/circuits/component/base.rb +++ b/lib/circuits/component/base.rb @@ -1,4 +1,5 @@ -require 'circuits/terminal' +require 'circuits/terminal/input' +require 'circuits/terminal/output' module Circuits # A component has a set of inputs an outputs. Every `tick` a componnent @@ -68,7 +69,7 @@ def create_inputs(opts) elsif opts[:inputs].class == Fixnum @input_count = opts[:inputs] end - @inputs ||= @input_count.times.collect { Circuits::Terminal.new } + @inputs ||= @input_count.times.collect { Circuits::Terminal::Input.new } end def create_outputs(opts) @@ -79,7 +80,7 @@ def create_outputs(opts) @output_count = opts[:outputs] end @outputs ||= @output_count.times.collect do - Circuits::Terminal.new + Circuits::Terminal::Output.new end end diff --git a/lib/circuits/component/nand.rb b/lib/circuits/component/nand.rb index 4f72cee..0e69056 100644 --- a/lib/circuits/component/nand.rb +++ b/lib/circuits/component/nand.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical NAND of the inputs def tick - outputs[0].set(!inputs.map(&:get).inject(:&)) + self[:out].set(!inputs.map(&:get).inject(:&)) end end end diff --git a/lib/circuits/component/nor.rb b/lib/circuits/component/nor.rb index 9221ce6..98f2ab2 100644 --- a/lib/circuits/component/nor.rb +++ b/lib/circuits/component/nor.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical OR of the inputs def tick - outputs[0].set(!inputs.map(&:get).inject(:|)) + self[:out].set(!inputs.map(&:get).inject(:|)) end end end diff --git a/lib/circuits/component/not.rb b/lib/circuits/component/not.rb index 8bb372a..ac695af 100644 --- a/lib/circuits/component/not.rb +++ b/lib/circuits/component/not.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical NOT of the inputs def tick - outputs[0].set(!inputs[0].get) + self[:out].set(!self[:in].get) end end end diff --git a/lib/circuits/component/or.rb b/lib/circuits/component/or.rb index dd42393..8aa26db 100644 --- a/lib/circuits/component/or.rb +++ b/lib/circuits/component/or.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical OR of the inputs def tick - outputs[0].set(inputs.map(&:get).inject(:|)) + self[:out].set(inputs.map(&:get).inject(:|)) end end end diff --git a/lib/circuits/component/sr_nand.rb b/lib/circuits/component/sr_nand.rb index 8c1c2a6..b185182 100644 --- a/lib/circuits/component/sr_nand.rb +++ b/lib/circuits/component/sr_nand.rb @@ -1,4 +1,5 @@ require 'circuits/component/base' +require 'circuits/component/nand' module Circuits module Component @@ -8,9 +9,9 @@ def initialize(opts = {}) set_defaults super opts create_sub_components + link_inputs + link_outputs link_sub_components - self[:q].set nand_1[:out] - self[:not_q].set nand_2[:out] end # Computes the outputs based on the inputs and previous state @@ -31,11 +32,19 @@ def create_sub_components @sub_components = [@nand_1, @nand_2] end + def link_inputs + nand_1[:a].set self[:not_s] + nand_2[:a].set self[:not_r] + end + + def link_outputs + self[:q].set nand_1[:out] + self[:not_q].set nand_2[:out] + end + def link_sub_components - nand_1[:a] = self[:not_s] - nand_2[:a] = self[:not_r] - nand_1[:b] = nand_2[:out] - nand_2[:b] = nand_1[:out] + nand_1[:b].set nand_2[:out] + nand_2[:b].set nand_1[:out] end def set_defaults diff --git a/lib/circuits/component/sr_nor.rb b/lib/circuits/component/sr_nor.rb index 28b9f52..12d1a05 100644 --- a/lib/circuits/component/sr_nor.rb +++ b/lib/circuits/component/sr_nor.rb @@ -1,4 +1,5 @@ require 'circuits/component/base' +require 'circuits/component/nor' module Circuits module Component @@ -8,9 +9,9 @@ def initialize(opts = {}) set_defaults super opts create_sub_components + link_inputs + link_outputs link_sub_components - self[:q].set nor_1[:out] - self[:not_q].set nor_2[:out] end # Computes the outputs based on the inputs and previous state @@ -31,11 +32,19 @@ def create_sub_components @sub_components = [@nor_1, @nor_2] end + def link_inputs + nor_1[:a].set self[:r] + nor_2[:a].set self[:s] + end + + def link_outputs + self[:q].set nor_1[:out] + self[:not_q].set nor_2[:out] + end + def link_sub_components - nor_1[:a] = self[:r] - nor_2[:a] = self[:s] - nor_1[:b] = nor_2[:out] - nor_2[:b] = nor_1[:out] + nor_1[:b].set nor_2[:out] + nor_2[:b].set nor_1[:out] end def set_defaults diff --git a/lib/circuits/component/xnor.rb b/lib/circuits/component/xnor.rb index 2ce8e3d..6091d90 100644 --- a/lib/circuits/component/xnor.rb +++ b/lib/circuits/component/xnor.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical XNOR of the inputs def tick - outputs[0].set(!inputs.map(&:get).inject(:^)) + self[:out].set(!inputs.map(&:get).inject(:^)) end end end diff --git a/lib/circuits/component/xor.rb b/lib/circuits/component/xor.rb index dc3dc98..e336076 100644 --- a/lib/circuits/component/xor.rb +++ b/lib/circuits/component/xor.rb @@ -12,7 +12,7 @@ def initialize(opts = {}) # Sets the output to be the result of a logical XOR of the inputs def tick - outputs[0].set(inputs.map(&:get).inject(:^)) + self[:out].set(inputs.map(&:get).inject(:^)) end end end diff --git a/lib/circuits/terminal.rb b/lib/circuits/terminal.rb deleted file mode 100644 index 44e6e92..0000000 --- a/lib/circuits/terminal.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Circuits - # A terminal holds a logical state, it can be attatched to components - class Terminal - # Creates the terminal - # @param opts [Hash] Options to create the Output with - # @option opts [Boolean] :state The initial state of the Output - def initialize(opts = {}) - @terminal = opts[:terminal] - @next_state = opts[:state] || false - @state = opts[:state] || false - end - - # Gets the state of the terminal - # @return [Boolean] The state of the output - def get - @state - end - - # The other terminal to read from next {#tock} or a state to be in now - # @param [Boolean, Terminal] terminal The terminal or state to output - def set(terminal) - if terminal.class == Terminal - @terminal = terminal - else - @terminal = nil - @state = @next_state = terminal - end - end - - # Sets the state to be that of the terminal or state last passed by {#set} - def tock - @state = @terminal.nil? ? @next_state : @terminal.get - end - end -end diff --git a/lib/circuits/terminal/input.rb b/lib/circuits/terminal/input.rb new file mode 100644 index 0000000..aefdf7b --- /dev/null +++ b/lib/circuits/terminal/input.rb @@ -0,0 +1,32 @@ +require 'circuits/terminal/output' + +module Circuits + # An input or an output to read from and set + module Terminal + # Reads from a single output + class Input + # Creates the input + # @param opts [Hash] Options to create the Input with + # @option opts [Component::Output] :output The output to read from + def initialize(opts = {}) + @terminal = opts[:terminal] || Output.new(state: opts[:state]) + end + + # Forward get to the output + # @return [Boolean] The state of the output + def get + @terminal.get + end + + # Output to use or state to make a dummy output with + # @param [Output, Boolean] output The output to read from, or state + def set(output) + if [Input, Output].include? output.class + @terminal = output + else + @terminal = Output.new(state: output) + end + end + end + end +end diff --git a/lib/circuits/terminal/output.rb b/lib/circuits/terminal/output.rb new file mode 100644 index 0000000..a294c4c --- /dev/null +++ b/lib/circuits/terminal/output.rb @@ -0,0 +1,36 @@ +module Circuits + # An input or an output to read from and set + module Terminal + # Gets set tcked then read + class Output + # Creates the output + # @param opts [Hash] Options to create the Output with + # @option opts [Boolean] :state The initial state of the Output + def initialize(opts = {}) + @next_state = opts[:terminal] || opts[:state] || false + tock + end + + # Gets the state of the terminal + # @return [Boolean] The state of the output + def get + @state + end + + # The next state + # @param [Boolean, Terminal] terminal The terminal or state to output + def set(state) + @next_state = state + end + + # Sets the state what was last set + def tock + if [Input, Output].include? @next_state.class + @state = @next_state.get + else + @state = @next_state + end + end + end + end +end diff --git a/lib/circuits/version.rb b/lib/circuits/version.rb index d6bb79c..3b8b371 100644 --- a/lib/circuits/version.rb +++ b/lib/circuits/version.rb @@ -1,5 +1,5 @@ # Circuits allows you to express logical circuits in code module Circuits # The version of the Circuits gem - VERSION = '0.6.0' + VERSION = '0.7.0' end diff --git a/spec/unit/circuits/terminal_spec.rb b/spec/unit/circuits/terminal_spec.rb deleted file mode 100644 index b6b3e52..0000000 --- a/spec/unit/circuits/terminal_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'spec_helper' -require 'circuits/terminal' - -describe Circuits::Terminal do - describe '#get' do - let(:state) { double('state') } - - context 'when given no state' do - subject { Circuits::Terminal.new } - - it 'is false' do - expect(subject.get).to eq(false) - end - end - - context 'when given a state' do - subject { Circuits::Terminal.new(state: state) } - - it 'has that state' do - expect(subject.get).to eq(state) - end - end - - context 'when given terminal' do - let(:terminal) { Circuits::Terminal.new(state: state) } - - subject { Circuits::Terminal.new(terminal: terminal) } - - it 'is false' do - expect(subject.get).to eq(false) - end - end - end - - describe '#set' do - let(:state_1) { double('state_1') } - let(:state_2) { double('state_2') } - - context 'when given a state' do - subject { Circuits::Terminal.new(state: state_1) } - - it 'gets set immediately' do - subject.set state_2 - expect(subject.get).to eq(state_2) - end - end - - context 'when given a terminal' do - let(:terminal) { Circuits::Terminal.new(state: state_2) } - - subject { Circuits::Terminal.new(state: state_1) } - - it 'gets does not get set immediately' do - subject.set terminal - expect(subject.get).to eq(state_1) - end - end - end - - describe '#tock' do - let(:state) { double('state') } - - context 'when passed a state' do - subject { Circuits::Terminal.new } - - it 'moves next set to get' do - subject.set state - subject.tock - expect(subject.get).to eq(state) - end - end - - context 'when given terminal' do - let(:terminal) { Circuits::Terminal.new(state: state) } - - subject { Circuits::Terminal.new(terminal: terminal) } - - it 'is has that state' do - subject.tock - expect(subject.get).to eq(state) - end - end - end -end