moory 0.3.3 → 0.4.0

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: 48186775b1c7f9b85822f58dadc0f2f355b1fc872e6ab7abcb1883da9b9d74e9
4
- data.tar.gz: 4edd7b2f0a957aaeb6d016d25b9fc7f638f69dc20e2d925c9a11b0a13863a092
3
+ metadata.gz: 28123aa5014d091460be8427c963f0cba5516dd319eca1e4e14ebcfed6fa4040
4
+ data.tar.gz: a6bfbc1b04c2ec1f2910f5eb01dc17515f99fe3ae6040ae4e5c48d03b39e5703
5
5
  SHA512:
6
- metadata.gz: a5c5a11ad922e36aa09687535e52273661520b64b42c0867a6d0f5c9b9b120a2408e98737515f10be6dfeffc83ee55b55a3699c8dc007e2c7b59b1b9b09b8a06
7
- data.tar.gz: 62c3df5b0cd326376f1434d2d6a8c3b3f3b7c1a3abdd05a0c9425f3f118bde51cccad786d48186d2155d7b32e900ef455858014fef72a9e581a8b367d19eae67
6
+ metadata.gz: 2e57244347beccfa883a776443b56b3beaed903a06582fec89810896546a180c191cb301384e1ebabac460b887f61706540c4fb6677ce0e1e0f6d70eea714138
7
+ data.tar.gz: 4cf05c5208129d257b6b3c7e4a5b139af5f64500c9aed726d1bcf1a53c8f8cd504af5756c5736dd023d0dab67dbe0fd22ba50212a3e88226dc1f8c8f0b75955c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- moory (0.3.3)
4
+ moory (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,14 +1,13 @@
1
1
  # Moory
2
2
  Welcome to the Moory gem!
3
3
 
4
- You can use this gem to create various kinds of finite machines using a simple specification language.
4
+ You can use this gem to create various kinds of finite machines, and even teach objects manners using a simple plain-text specification language.
5
5
 
6
- The [wiki](https://github.com/elclavijero/moory/wiki) is where to go if you are for looking for tutorial material. Perhaps also look in the examples directory. Therein you'll find use of the Acceptor, Decoder (Mealy machine), and something useless but (hopefully) illuminating.
6
+ The [wiki](https://github.com/elclavijero/moory/wiki) is where to go if you are for looking for tutorial material. Perhaps also look in the examples directory.
7
7
 
8
- Until you do, here is an example showing how you might use the Acceptor.
8
+ Until you do, here are two examples: the first is an acceptor, and the second is a **well mannered** object.
9
9
 
10
-
11
- ## Example: Creating an acceptor for ab*
10
+ ## Example: An acceptor for ab*
12
11
 
13
12
  ### Motivation
14
13
 
@@ -88,9 +87,117 @@ ab_star.accepts?(string: "abcbb")
88
87
 
89
88
  That's better.
90
89
 
90
+ ## Example: A well mannered object
91
+ If you haven't already, open up `irb` and create an uncouth object
92
+
93
+ ```ruby
94
+ uncouth = Object.new
95
+ ```
96
+
97
+ and teach it how to speak
98
+
99
+ ```ruby
100
+ def uncouth.say_foo
101
+ p 'foo'
102
+ end
103
+ def uncouth.say_bar
104
+ p 'bar'
105
+ end
106
+ def uncouth.say_something_nice(name)
107
+ p "Hello, #{name}. You look nice."
108
+ end
109
+ ```
110
+
111
+ Do you see anything wrong here? Doesn't that object seem a little dangerous? Everybody knows that `"foo"` comes before `"bar"` in code examples. That absurd object might ruin everything! Is there anything we can do to prevent it from doing the unthinkable?
112
+
113
+ ```ruby
114
+ uncouth.say_bar
115
+ uncouth.say_foo
116
+ ```
117
+
118
+ Yes. We can filter calls to the uncouth object using Moory's WellMannered class. We need it's methods to be called according to foo-bar-etiquette:
119
+
120
+ ![ab_star](images/foo_bar_etiquette.png)
121
+
122
+ Let's describe those rules using a language Moory understands:
123
+
124
+ ```ruby
125
+ the_rules_of_foo_bar_etiquette = """
126
+ start : say_foo : said_foo
127
+
128
+ said_foo : say_foo : said_foo
129
+ said_foo : say_bar : said_foo_bar
130
+
131
+ said_foo_bar : say_foo : said_foo_bar
132
+ said_foo_bar : say_bar : said_foo_bar
133
+ """
134
+ ```
135
+
136
+ Let's make a postive change, and hereon refer to the uncouth object as the `well_mannered_object`.
137
+ It will be our `protege`:
138
+
139
+ ```ruby
140
+ require 'moory'
141
+
142
+ well_mannered_object = Moory::WellMannered.new(
143
+ protege: uncouth,
144
+ rules: the_rules_of_foo_bar_etiquette
145
+ )
146
+ ```
147
+ Now let's have a conversation with our protege.
148
+ ```ruby
149
+ well_mannered_object.say_something_nice('Adam')
150
+ # "Hello, Adam. You look nice."
151
+ ```
152
+ That is nice.
153
+ ```ruby
154
+ well_mannered_object.say_bar
155
+ ```
156
+ So far so good. Our well mannered object is proving to be polite. If someone asks it to depart from protocol, it will just quietly refuse. But what if that isn't enough? What should it do if someone asks it to do something really bad? The trouble is that well mannered objects are so well-behaved, they won't do depart from the protocol unless we say its OK. Let's do that.
157
+
158
+ ```ruby
159
+ well_mannered_object.response_to_rule_breaking = proc { |msg|
160
+ p "You shouldn't ask me to #{msg}! I'm telling!"
161
+ }
162
+ ```
163
+
164
+ Now when we ask it to do something it out of turn
165
+ ```ruby
166
+ well_mannered_object.say_bar
167
+ # "You shouldn't ask me to say_bar! I'm telling!"
168
+ ```
169
+ it will tell on you. What a nice object! Now don't be such a telltale.
170
+ ```ruby
171
+ well_mannered_object.response_to_rule_breaking = nil
172
+ ```
173
+ Let's continue
174
+ ```ruby
175
+ well_mannered_object.say_bar
176
+ ```
177
+ Good. You didn't complain.
178
+ ```ruby
179
+ well_mannered_object.say_foo
180
+ # "foo"
181
+ ```
182
+ Promising. You haven't yet spoken out of turn.
183
+ ```ruby
184
+ well_mannered_object.say_foo
185
+ # "foo"
186
+ ```
187
+ A perfectly acceptable reptition.
188
+ ```ruby
189
+ well_mannered_object.say_bar
190
+ # "bar"
191
+ ```
192
+ Wonderful!
193
+ ```ruby
194
+ well_mannered_object.say_something_nice('Adam')
195
+ ```
196
+ Yes. Thank you.
197
+
91
198
  ### Before you go...
92
199
 
93
- There's more to Moory than its Acceptor. I'll show you how to use its other features in the [wiki](https://github.com/elclavijero/moory/wiki).
200
+ There's more to Moory than its Acceptors and WellMannered objects. I'll show you how to use its other features in the [wiki](https://github.com/elclavijero/moory/wiki).
94
201
 
95
202
 
96
203
  ## Installation
@@ -0,0 +1,81 @@
1
+ # Well-mannered objects
2
+
3
+ # Suppose we have an uncouth object
4
+ uncouth = Object.new
5
+
6
+ # and it can speak
7
+ def uncouth.say_foo
8
+ p 'foo'
9
+ end
10
+ def uncouth.say_bar
11
+ p 'bar'
12
+ end
13
+ def uncouth.say_something_nice(name)
14
+ p "Hello, #{name}. You look nice."
15
+ end
16
+
17
+ # Do you see anything wrong here?
18
+ # Doesn't that object seem a little dangerous? Everybody knows that "foo" comes before "bar" in
19
+ # code examples. That absurd object might ruin everything! Is there anything we can do to prevent
20
+ # it from doing the unthinkable?
21
+ #
22
+ # uncouth.say_bar
23
+ # uncouth.say_foo
24
+ #
25
+
26
+ # Yes, of course there is! We can filter calls to the uncouth object using Moory's WellManered
27
+ # class.
28
+ require 'moory'
29
+
30
+ # We can go no further until we write down the rules of foo-bar-etiquette
31
+
32
+ the_rules_of_foo_bar_etiquette = """
33
+ start : say_foo : said_foo
34
+
35
+ said_foo : say_foo : said_foo
36
+ said_foo : say_bar : said_foo_bar
37
+
38
+ said_foo_bar : say_foo : said_foo_bar
39
+ said_foo_bar : say_bar : said_foo_bar
40
+ """
41
+
42
+ # Let's make a postive change, and hereon refer to the uncouth object as the `well_mannered_object`.
43
+ # It will be our `protege`, and the instantiation of a WellMannered object won't surprise us:
44
+
45
+ well_mannered_object = Moory::WellMannered.new(
46
+ protege: uncouth,
47
+ rules: the_rules_of_foo_bar_etiquette
48
+ )
49
+
50
+ # Now let's have a conversation with our protege.
51
+ well_mannered_object.say_something_nice('Adam')
52
+ # That is nice.
53
+ well_mannered_object.say_bar
54
+ # Good. I'm glad you didn't fall for that
55
+
56
+ # So far so good. Our well mannered object is proving to be polite. If someone asks it
57
+ # to depart from protocol, it will just quietly refuse. But what if that isn't enough?
58
+ # What should it do if someone asks it to do something really bad? The trouble is,
59
+ # well-mannered objects are so well-behaved, they won't do anything unless we say its OK.
60
+ # Let's do that.
61
+
62
+ well_mannered_object.response_to_rule_breaking = proc { |msg|
63
+ pp "You shouldn't ask me to #{msg}! I'm telling!"
64
+ }
65
+
66
+ # Now when we ask it to do something it out of turn
67
+ well_mannered_object.say_bar
68
+ # it will tell on you. What a nice object! Now don't be such a telltale.
69
+ well_mannered_object.response_to_rule_breaking = nil
70
+ # Let's continue
71
+ well_mannered_object.say_bar
72
+ # Good. You didn't complain.
73
+ well_mannered_object.say_foo
74
+ # Promising. You haven't yet spoken out of turn.
75
+ well_mannered_object.say_foo
76
+ # A perfectly acceptable reptition.
77
+ well_mannered_object.say_bar
78
+ # Wonderful!
79
+ well_mannered_object.say_something_nice('Adam')
80
+ # Yes. Thank you.
81
+
Binary file
data/lib/moory.rb CHANGED
@@ -3,6 +3,7 @@ require "moory/interpreter"
3
3
  require "moory/parser"
4
4
  require "moory/acceptor"
5
5
  require "moory/decoder"
6
+ require "moory/wellmannered"
6
7
 
7
8
  module Moory
8
9
  # Your code goes here...
data/lib/moory/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Moory
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -0,0 +1,54 @@
1
+ module Moory
2
+ class WellMannered
3
+ attr_reader :response_to_rule_breaking
4
+
5
+ IGNORE = proc {}
6
+
7
+ def initialize(protege:, rules:, initial:'start', response_to_rule_breaking: IGNORE)
8
+ @protege = protege
9
+ @rules = rules
10
+ @initial = initial
11
+ @response_to_rule_breaking = response_to_rule_breaking
12
+ prepare
13
+ end
14
+
15
+ def restricted_messages
16
+ interpreter.alphabet
17
+ end
18
+
19
+ def response_to_rule_breaking=(obj)
20
+ @response_to_rule_breaking = obj.respond_to?(:call) ? obj : IGNORE
21
+ end
22
+
23
+ private
24
+
25
+ def prepare
26
+ interpreter.load(@rules)
27
+ interpreter.state = @initial
28
+ end
29
+
30
+ def interpreter
31
+ @interpreter ||= Moory::Interpreter.new
32
+ end
33
+
34
+ def method_missing(*args)
35
+ protected?(*args) ?
36
+ filter_first(*args) :
37
+ forward(*args)
38
+ end
39
+
40
+ def protected?(*args)
41
+ interpreter.alphabet.include?(args.first.to_s)
42
+ end
43
+
44
+ def filter_first(*args)
45
+ interpreter.putm(args.first.to_s) ?
46
+ forward(*args) :
47
+ response_to_rule_breaking.call(*args)
48
+ end
49
+
50
+ def forward(*args)
51
+ @protege.send(*args)
52
+ end
53
+ end
54
+ end
data/moory.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Adam W. Grant"]
10
10
  spec.email = ["adam_grnt@yahoo.co.uk"]
11
11
 
12
- spec.summary = %q{Use plain text to define finite machines.}
12
+ spec.summary = %q{Use plain text to define finite machines (and even teach objects manners) using a simple plain-text specification language.}
13
13
  spec.license = "MIT"
14
14
 
15
15
  spec.homepage = 'https://github.com/elclavijero/moory'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam W. Grant
@@ -73,13 +73,16 @@ files:
73
73
  - examples/readme_example.rb
74
74
  - examples/silly.rb
75
75
  - examples/single_as_and_bs.rb
76
+ - examples/well_mannered_objects.rb
76
77
  - images/ab_star.png
78
+ - images/foo_bar_etiquette.png
77
79
  - lib/moory.rb
78
80
  - lib/moory/acceptor.rb
79
81
  - lib/moory/decoder.rb
80
82
  - lib/moory/interpreter.rb
81
83
  - lib/moory/parser.rb
82
84
  - lib/moory/version.rb
85
+ - lib/moory/wellmannered.rb
83
86
  - moory.gemspec
84
87
  homepage: https://github.com/elclavijero/moory
85
88
  licenses:
@@ -104,5 +107,6 @@ rubyforge_project:
104
107
  rubygems_version: 2.7.6
105
108
  signing_key:
106
109
  specification_version: 4
107
- summary: Use plain text to define finite machines.
110
+ summary: Use plain text to define finite machines (and even teach objects manners)
111
+ using a simple plain-text specification language.
108
112
  test_files: []