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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +113 -6
- data/examples/well_mannered_objects.rb +81 -0
- data/images/foo_bar_etiquette.png +0 -0
- data/lib/moory.rb +1 -0
- data/lib/moory/version.rb +1 -1
- data/lib/moory/wellmannered.rb +54 -0
- data/moory.gemspec +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28123aa5014d091460be8427c963f0cba5516dd319eca1e4e14ebcfed6fa4040
|
|
4
|
+
data.tar.gz: a6bfbc1b04c2ec1f2910f5eb01dc17515f99fe3ae6040ae4e5c48d03b39e5703
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e57244347beccfa883a776443b56b3beaed903a06582fec89810896546a180c191cb301384e1ebabac460b887f61706540c4fb6677ce0e1e0f6d70eea714138
|
|
7
|
+
data.tar.gz: 4cf05c5208129d257b6b3c7e4a5b139af5f64500c9aed726d1bcf1a53c8f8cd504af5756c5736dd023d0dab67dbe0fd22ba50212a3e88226dc1f8c8f0b75955c
|
data/Gemfile.lock
CHANGED
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.
|
|
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
|
|
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
|
+

|
|
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
|
|
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
data/lib/moory/version.rb
CHANGED
|
@@ -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.
|
|
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: []
|