yatm 0.2.0 → 0.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be3ead1b208b860b2ef2021496657196eff8a1bc42fc25c569cf77d3be6f37ff
4
- data.tar.gz: a502d0f27f32c4a8686f5edca9aaf6e53f842a524b3e6cd26f34140528966bc5
3
+ metadata.gz: 648dc35601df1be85b015a29fff60f789820bd605e8b90e2f2b78d81fd9ec749
4
+ data.tar.gz: 9fad47b236af179fed6869d7813ecfa37da86fe7c8a06e53bd8abe07dde1b819
5
5
  SHA512:
6
- metadata.gz: 8f63ffe798d7500425b9d2de058fbc4704584b5a9b3fbc20ac440677df16b5b1a1d1fb512cc5c3efcf5e97fb5c89d974c5cf15560cf8fad22bf54e511bdd9602
7
- data.tar.gz: fa8a1cfef51c8cc0673a17c461e53319ab3d953e7cc8b85803e6136a3f010665c27992d7ae26f83f0bcfa162369691e9778414d88e9391ef31f88b1212bb8e5d
6
+ metadata.gz: acd14ce8af175e496e737be3e67d91045456a8c8334d9cac9a90e7122989e0f727f40780f3ca9e641cdf128533eca3e395cb6f614188c67c9184f7953d63a571
7
+ data.tar.gz: da9d9e6e5ab7dcb3ec5c3bb4c0c3bded322140d509774c33b3c4ebd6257904f0d4f272d5e02d7087df4ec41fbcc30ea7748a334ebc52c7b57203ee33962fee76
data/lib/yatm/error.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # @abstract Subclass and override {#text} to set the default error message.
3
4
  class YATM::Error < StandardError
4
5
  def text
5
6
  raise NotImplementedError
@@ -1,18 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # This is the class used to set up and use the turing machine.
4
+ #
5
+ # Use {#event} to create the various transitions. The states are automatically
6
+ # inferred to be all the states added through this method.
7
+ #
8
+ # Use {#initial_state} once to select the initial state, and {#final_state}
9
+ # however many times to mark states as final.
10
+ #
11
+ # The content of the tape can be given upon initializing the machine, through
12
+ # the parameter `content`, or with the method {#reset}.
13
+ #
14
+ # @example A turing machine which prints an "OX" and halts at position 0.
15
+ # m = YATM::Machine.new
16
+ # m.event nil,
17
+ # start: [:running, "O", :r],
18
+ # running: [:halt, "X", :l]
19
+ # m.initial_state :start
20
+ # m.final_state :halt
21
+ # m.run!
3
22
  class YATM::Machine
4
- attr_reader :tape, :state_machine, :history
5
-
23
+ # The tape over which values can be written and read by the machine.
24
+ attr_reader :tape
25
+ # The state machine associated with this turing machine.
26
+ attr_reader :state_machine
27
+ # @return [Array<Hash>] A record of the transitions undergone by the machine.
28
+ attr_reader :history
29
+
30
+ # @param position [Integer] The initial position of the machine's head.
31
+ # @param content [Array] The initial content of the tape, starting from position 0.
6
32
  def initialize(position: 0, content: [nil])
7
33
  @tape = YATM::Tape.new(content, position: position)
8
34
  @state_machine = YATM::StateMachine.new
9
35
  @history = []
10
36
  end
11
37
 
38
+ # @param state [String, Symbol, Number] The state to be set as the starting state.
39
+ # @return [String, Symbol, Number] The initial state.
12
40
  def initial_state(...); @state_machine.initial_state(...); end
13
41
 
42
+ # (see YATM::StateMachine#final_state)
14
43
  def final_state(...); @state_machine.final_state(...); end
15
44
 
45
+ # (see YATM::StateMachine#states)
16
46
  def states(...); @state_machine.states(...); end
17
47
 
18
48
  def events(...); @state_machine.events(...); end
@@ -4,7 +4,12 @@ require_relative "state_machine_errors"
4
4
  require_relative "event"
5
5
 
6
6
  class YATM::StateMachine
7
- attr_reader :current_state, :events, :final_states, :initial_state
7
+ # The current state of the state machine
8
+ attr_reader :current_state
9
+ # @return [Array<YATM::StateMachine::Event>] A list of the events that can processed by the machine
10
+ attr_reader :events
11
+ # @return [Array] A list of the final states
12
+ attr_reader :final_states
8
13
 
9
14
  def initialize
10
15
  @events = {}
@@ -15,6 +20,14 @@ class YATM::StateMachine
15
20
  @current_state = @initial_state
16
21
  end
17
22
 
23
+ # @return [String] A string representation of the state machine
24
+ #
25
+ # @example Example output
26
+ # puts state_machine.to_s
27
+ #
28
+ # | states: [:start, :A, :B, :end]
29
+ # | current: :start
30
+ # | events: [nil, 0, 1]
18
31
  def to_s
19
32
  <<~TO_S.chomp
20
33
  | states: #{states}
@@ -23,33 +36,73 @@ class YATM::StateMachine
23
36
  TO_S
24
37
  end
25
38
 
39
+ # @return [Array] The list of all states of the state machine
26
40
  def states
27
41
  @events.map do |_name, event|
28
42
  event.keys + event.map { |_, val| val[:to] }
29
43
  end.flatten.uniq
30
44
  end
31
45
 
32
- def initial_state(state)
46
+ # @overload initial_state(state)
47
+ # @param state [#to_s && #to_sym] The state to be set as the starting state
48
+ # @return [Object] The initial state
49
+ # @overload initial_state
50
+ # @return [Object] The initial state
51
+ #
52
+ # @see states
53
+ def initial_state(state = nil)
54
+ return @initial_state if state.nil?
55
+
33
56
  @initial_state = self.class.statify(state)
34
57
  @current_state = @initial_state
35
58
  end
36
59
 
60
+ # @param states [#to_s && #to_sym] The state or array of states to be marked
61
+ # as final states
62
+ # @return [Array] The complete list of final states
37
63
  def final_state(*states)
38
64
  states.each do |state|
39
65
  (@final_states << self.class.statify(state)).uniq!
40
66
  end
67
+ @final_states
41
68
  end
42
69
 
70
+ # @param name [Object] The name of the event.
71
+ #
72
+ # Note that this is also the value which, when read from the tape, will
73
+ # trigger the processing of this event.
74
+ # @param **transitions [Hash | Hash[, Hash...]] One or more transitions.
75
+ #
76
+ # Transitions can be of the following forms:
77
+ # - `state1 => [state2, value, movement]`
78
+ # - `state1 => [state2, value]`
79
+ # - `state1 => [state2]`
80
+ # - `state1 => state2`
81
+ # On all cases, the machine is going from `state1` to `state2`, writing
82
+ # `value` on the current position of the tape, and moving the head in the
83
+ # direction specified by `movement`.
84
+ # @return [YATM::StateMachine::Event] The event object creared
43
85
  def event(name, **transitions)
44
86
  @events[name] = YATM::Event.new(name, **transitions)
45
87
  end
46
88
 
89
+ # @param value [Object] Tape value to be processed (trigger corresponding
90
+ # event) by the machine
91
+ # @return [Hash | nil] A representation of the transition which was triggered,
92
+ # or nil if none was
47
93
  def process(value)
48
94
  process!(value)
49
95
  rescue StateMachineError
50
96
  nil
51
97
  end
52
98
 
99
+ # @param value [Object] Tape value to be processed (trigger corresponding
100
+ # event) by the machine
101
+ # @return [Hash] A representation of the transition which was triggered
102
+ # @raise [InitialStateNotSet] No initial state was set. See {initial_state}
103
+ # @raise [InvalidEvent] There is no event registered under the given value
104
+ # @raise [InvalidTransition] There is an event registered under the given
105
+ # value, but it contains no transitions from the machine's current state
53
106
  def process!(value)
54
107
  return { final: @current_state } if @final_states.include?(@current_state)
55
108
  raise InitialStateNotSet unless @current_state
@@ -62,12 +115,24 @@ class YATM::StateMachine
62
115
  transition
63
116
  end
64
117
 
65
- def self.statify(state)
66
- raise InvalidState, state unless state.respond_to?(:to_s)
118
+ class << self
119
+ # @param state [#to_s && #to_sym] The object to be statified
120
+ # @return [Symbol] The object's statified form
121
+ # @raise [InvalidState] The object given could not be statified
122
+ def statify!(state)
123
+ raise InvalidState, state unless state.respond_to?(:to_s)
124
+
125
+ state = state.to_s
126
+ raise InvalidState, state unless state.respond_to?(:to_sym)
67
127
 
68
- state = state.to_s
69
- raise InvalidState, state unless state.respond_to?(:to_sym)
128
+ state.to_sym
129
+ end
70
130
 
71
- state.to_sym
131
+ # @param state [#to_s && #to_sym] The object to be statified
132
+ # @return [Symbol | nil] If the object could be statified, it's statified
133
+ # form. Nil otherwise
134
+ def statify(state)
135
+ statify!(state) rescue StateMachineError
136
+ end
72
137
  end
73
138
  end
@@ -32,6 +32,7 @@ class YATM::Tape
32
32
  @pos -= 1
33
33
  expand if table_pos > tape.size
34
34
  when YATM::NONE
35
+ # do nothing
35
36
  else
36
37
  raise InvalidMove
37
38
  end
data/lib/yatm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YATM
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/yatm.rb CHANGED
@@ -5,6 +5,7 @@ require_relative "yatm/tape/tape"
5
5
  require_relative "yatm/state_machine/state_machine"
6
6
  require_relative "yatm/machine/machine"
7
7
 
8
+ # This is the main module.
8
9
  module YATM
9
10
  ANY = :*
10
11
  SAME = :_
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yatm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - tiago-macedo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-19 00:00:00.000000000 Z
11
+ date: 2022-09-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  This gem provides you with the module `YATM`.