calyx 0.11.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +75 -31
- data/examples/faker.rb +7 -0
- data/examples/faker.yml +42 -0
- data/lib/calyx/errors.rb +51 -4
- data/lib/calyx/format.rb +22 -7
- data/lib/calyx/grammar.rb +73 -2
- data/lib/calyx/modifiers.rb +11 -4
- data/lib/calyx/production/choices.rb +13 -0
- data/lib/calyx/production/concat.rb +17 -0
- data/lib/calyx/production/expression.rb +11 -0
- data/lib/calyx/production/memo.rb +10 -0
- data/lib/calyx/production/non_terminal.rb +10 -0
- data/lib/calyx/production/terminal.rb +7 -0
- data/lib/calyx/production/weighted_choices.rb +19 -1
- data/lib/calyx/registry.rb +50 -3
- data/lib/calyx/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75811b39e9ca016645eb82dea083ff50612f8e2b
|
4
|
+
data.tar.gz: af905efd81c6b0e679e2ed333f571fdad65ee8a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97a47ba2a0dcf0d658641ba1f67b3237731132ca0500c92053b86f54a60b2eba7f3181daef54c43f94d40c725915c39a2ae2898d6a639a0399f3910a4d01116f
|
7
|
+
data.tar.gz: 57341f9c8428917d56b33dedd219dd904bca3252b9f2a7d240bcab1a050f8209f7b61ab26d9402b69f029be53d7ffcfcd29b8342777e2de62733e408607af872
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ gem 'calyx'
|
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
|
-
Require the library and inherit from `Calyx::Grammar` to construct a set of rules to generate a text.
|
24
|
+
Require the library and inherit from `Calyx::Grammar` to construct a set of rules to generate a text.
|
25
25
|
|
26
26
|
```ruby
|
27
27
|
require 'calyx'
|
@@ -39,12 +39,12 @@ hello.generate
|
|
39
39
|
# > "Hello world."
|
40
40
|
```
|
41
41
|
|
42
|
-
Obviously, this hardcoded sentence isn’t very interesting by itself. Possible variations can be added to the text
|
42
|
+
Obviously, this hardcoded sentence isn’t very interesting by itself. Possible variations can be added to the text by adding additional rules which provide a named set of text strings. The rule delimiter syntax (`{}`) can be used to substitute the generated content of other rules.
|
43
43
|
|
44
44
|
```ruby
|
45
45
|
class HelloWorld < Calyx::Grammar
|
46
46
|
start '{greeting} world.'
|
47
|
-
|
47
|
+
greeting 'Hello', 'Hi', 'Hey', 'Yo'
|
48
48
|
end
|
49
49
|
```
|
50
50
|
|
@@ -63,6 +63,17 @@ hello.generate
|
|
63
63
|
# > "Yo world."
|
64
64
|
```
|
65
65
|
|
66
|
+
By convention, the `start` rule specifies the default starting point for generating the final text. You can start from any other named rule by passing it explicitly to the generate method.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class HelloWorld < Calyx::Grammar
|
70
|
+
hello 'Hello world.'
|
71
|
+
end
|
72
|
+
|
73
|
+
hello = HelloWorld.new
|
74
|
+
hello.generate(:hello)
|
75
|
+
```
|
76
|
+
|
66
77
|
### Block Constructors
|
67
78
|
|
68
79
|
As an alternative to subclassing, you can also construct rules unique to an instance by passing a block when initializing the class:
|
@@ -70,12 +81,44 @@ As an alternative to subclassing, you can also construct rules unique to an inst
|
|
70
81
|
```ruby
|
71
82
|
hello = Calyx::Grammar.new do
|
72
83
|
start '{greeting} world.'
|
73
|
-
|
84
|
+
greeting 'Hello', 'Hi', 'Hey', 'Yo'
|
74
85
|
end
|
75
86
|
|
76
87
|
hello.generate
|
77
88
|
```
|
78
89
|
|
90
|
+
### External File Formats
|
91
|
+
|
92
|
+
In addition to defining grammars in pure Ruby, you can load them from external JSON and YAML files:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
hello = Calyx::Grammar.load('hello.yml')
|
96
|
+
hello.generate
|
97
|
+
```
|
98
|
+
|
99
|
+
The format requires a flat map with keys representing the left-hand side named symbols and the values representing the right hand side substitution rules.
|
100
|
+
|
101
|
+
In JSON:
|
102
|
+
|
103
|
+
```json
|
104
|
+
{
|
105
|
+
"start": "{greeting} world.",
|
106
|
+
"greeting": ["Hello", "Hi", "Hey", "Yo"]
|
107
|
+
}
|
108
|
+
```
|
109
|
+
|
110
|
+
In YAML:
|
111
|
+
|
112
|
+
```yaml
|
113
|
+
---
|
114
|
+
start: "{greeting} world."
|
115
|
+
greeting:
|
116
|
+
- Hello
|
117
|
+
- Hi
|
118
|
+
- Hey
|
119
|
+
- Yo
|
120
|
+
```
|
121
|
+
|
79
122
|
### Nesting and Substitution
|
80
123
|
|
81
124
|
Rules are recursive. They can be arbitrarily nested and connected to generate larger and more complex texts.
|
@@ -83,10 +126,10 @@ Rules are recursive. They can be arbitrarily nested and connected to generate la
|
|
83
126
|
```ruby
|
84
127
|
class HelloWorld < Calyx::Grammar
|
85
128
|
start '{greeting} {world_phrase}.'
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
129
|
+
greeting 'Hello', 'Hi', 'Hey', 'Yo'
|
130
|
+
world_phrase '{happy_adj} world', '{sad_adj} world', 'world'
|
131
|
+
happy_adj 'wonderful', 'amazing', 'bright', 'beautiful'
|
132
|
+
sad_adj 'cruel', 'miserable'
|
90
133
|
end
|
91
134
|
```
|
92
135
|
|
@@ -96,18 +139,18 @@ Nesting and hierarchy can be manipulated to balance consistency with novelty. Th
|
|
96
139
|
module HelloWorld
|
97
140
|
class Sentiment < Calyx::Grammar
|
98
141
|
start '{happy_phrase}', '{sad_phrase}'
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
142
|
+
happy_phrase '{happy_greeting} {happy_adj} world.'
|
143
|
+
happy_greeting 'Hello', 'Hi', 'Hey', 'Yo'
|
144
|
+
happy_adj 'wonderful', 'amazing', 'bright', 'beautiful'
|
145
|
+
sad_phrase '{sad_greeting} {sad_adj} world.'
|
146
|
+
sad_greeting 'Goodbye', 'So long', 'Farewell'
|
147
|
+
sad_adj 'cruel', 'miserable'
|
105
148
|
end
|
106
149
|
|
107
150
|
class Mixed < Calyx::Grammar
|
108
151
|
start '{greeting} {adj} world.'
|
109
|
-
|
110
|
-
|
152
|
+
greeting 'Hello', 'Hi', 'Hey', 'Yo', 'Goodbye', 'So long', 'Farewell'
|
153
|
+
adj 'wonderful', 'amazing', 'bright', 'beautiful', 'cruel', 'miserable'
|
111
154
|
end
|
112
155
|
end
|
113
156
|
```
|
@@ -147,7 +190,7 @@ class Roll2D6 < Calyx::Grammar
|
|
147
190
|
end
|
148
191
|
```
|
149
192
|
|
150
|
-
Or reproduce Gary Gygax’s famous generation table from the original Dungeon Master’s Guide (page 171):
|
193
|
+
Or reproduce Gary Gygax’s famous generation table from the original [Dungeon Master’s Guide](https://en.wikipedia.org/wiki/Dungeon_Master%27s_Guide#Advanced_Dungeons_.26_Dragons) (page 171):
|
151
194
|
|
152
195
|
```ruby
|
153
196
|
class ChamberOrRoomContents < Calyx::Grammar
|
@@ -160,12 +203,12 @@ class ChamberOrRoomContents < Calyx::Grammar
|
|
160
203
|
[:treasure, 0.05]
|
161
204
|
)
|
162
205
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
206
|
+
empty 'Empty'
|
207
|
+
monster 'Monster Only'
|
208
|
+
monster_treasure 'Monster and Treasure'
|
209
|
+
special 'Special'
|
210
|
+
trick_trap 'Trick/Trap.'
|
211
|
+
treasure 'Treasure'
|
169
212
|
end
|
170
213
|
```
|
171
214
|
|
@@ -176,8 +219,8 @@ Basic rule substitution uses single curly brackets as delimiters for template ex
|
|
176
219
|
```ruby
|
177
220
|
class Fruit < Calyx::Grammar
|
178
221
|
start '{colour} {fruit}'
|
179
|
-
|
180
|
-
|
222
|
+
colour 'red', 'green', 'yellow'
|
223
|
+
fruit 'apple', 'pear', 'tomato'
|
181
224
|
end
|
182
225
|
```
|
183
226
|
|
@@ -188,7 +231,7 @@ Dot-notation is supported in template expressions, allowing you to call any avai
|
|
188
231
|
```ruby
|
189
232
|
class Greeting < Calyx::Grammar
|
190
233
|
start '{hello.capitalize} there.', 'Why, {hello} there.'
|
191
|
-
|
234
|
+
hello 'hello'
|
192
235
|
end
|
193
236
|
|
194
237
|
# => "Hello there."
|
@@ -206,8 +249,9 @@ class Greeting < Calyx::Grammar
|
|
206
249
|
filter :shoutycaps do |input|
|
207
250
|
input.upcase
|
208
251
|
end
|
252
|
+
|
209
253
|
start '{hello.shoutycaps} there.', 'Why, {hello} there.'
|
210
|
-
|
254
|
+
hello 'hello'
|
211
255
|
end
|
212
256
|
|
213
257
|
# => "HELLO there."
|
@@ -222,7 +266,7 @@ The mapping shortcut allows you to specify a map of regex patterns pointing to t
|
|
222
266
|
class GreenBottle < Calyx::Grammar
|
223
267
|
mapping :pluralize, /(.+)/ => '\\1s'
|
224
268
|
start 'One green {bottle}.', 'Two green {bottle.pluralize}.'
|
225
|
-
|
269
|
+
bottle 'bottle'
|
226
270
|
end
|
227
271
|
|
228
272
|
# => "One green bottle."
|
@@ -243,7 +287,7 @@ end
|
|
243
287
|
class Hello < Calyx::Grammar
|
244
288
|
modifier FullStop
|
245
289
|
start '{hello.capitalize.full_stop}'
|
246
|
-
|
290
|
+
hello 'hello'
|
247
291
|
end
|
248
292
|
|
249
293
|
# => "Hello."
|
@@ -282,7 +326,7 @@ end
|
|
282
326
|
|
283
327
|
class NounsWithArticles < Calyx::Grammar
|
284
328
|
start '{fruit.with_indefinite_article.capitalize.full_stop}'
|
285
|
-
|
329
|
+
fruit 'apple', 'orange', 'banana', 'pear'
|
286
330
|
end
|
287
331
|
|
288
332
|
# => "An apple."
|
@@ -372,7 +416,7 @@ Rough plan for stabilising the API and features for a `1.0` release.
|
|
372
416
|
| `0.8` | ~~method missing metaclass API~~ |
|
373
417
|
| `0.9` | ~~return grammar tree from `#evaluate`, with flattened string from `#generate` being separate~~ |
|
374
418
|
| `0.10` | ~~inject custom string functions for parameterised rules, transforms and mappings~~ |
|
375
|
-
| `0.11` | support YAML format (and JSON?) |
|
419
|
+
| `0.11` | ~~support YAML format (and JSON?)~~ |
|
376
420
|
| `1.0` | API documentation |
|
377
421
|
|
378
422
|
## Credits
|
data/examples/faker.rb
ADDED
data/examples/faker.yml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
email: "{username}@{domain}"
|
2
|
+
full_name:
|
3
|
+
- "{first_name} {last_name}"
|
4
|
+
- "{first_name} {first_name.chars.first} {last_name}"
|
5
|
+
username:
|
6
|
+
- "{first_name.downcase}"
|
7
|
+
- "{first_name.downcase}{number}"
|
8
|
+
first_name: [Aaliyah, Aaron, Abagail, Abbey, Abbie, Abbigail, Abby, Abdiel, Abdul, Abdullah, Abe, Abel, Abelardo, Abigail, Abigale, Abigayle, Abner, Abraham, Ada, Adah, Adalberto, Adaline, Adam, Adan, Addie, Addison, Adela, Adelbert, Adele, Adelia, Adeline, Adell, Adella, Adelle, Aditya, Adolf, Adolfo, Adolph, Adolphus, Adonis, Adrain, Adrian, Adriana, Adrianna, Adriel, Adrien, Adrienne, Afton, Aglae, Agnes, Agustin, Agustina, Ahmad, Ahmed, Aida, Aidan, Aiden, Aileen, Aimee, Aisha, Aiyana, Akeem, Al, Alaina, Alan, Alana, Alanis, Alanna, Alayna, Alba, Albert, Alberta, Albertha, Alberto, Albin, Albina, Alda, Alden, Alec, Aleen, Alejandra, Alejandrin, Alek, Alena, Alene, Alessandra, Alessandro, Alessia, Aletha, Alex, Alexa, Alexander, Alexandra, Alexandre, Alexandrea, Alexandria, Alexandrine, Alexandro, Alexane, Alexanne, Alexie, Alexis, Alexys, Alexzander, Alf, Alfonso, Alfonzo, Alford, Alfred, Alfreda, Alfredo, Ali, Alia, Alice, Alicia, Alisa, Alisha, Alison, Alivia, Aliya, Aliyah, Aliza, Alize, Allan, Allen, Allene, Allie, Allison, Ally, Alphonso, Alta, Althea, Alva, Alvah, Alvena, Alvera, Alverta, Alvina, Alvis, Alyce, Alycia, Alysa, Alysha, Alyson, Alysson, Amalia, Amanda, Amani, Amara, Amari, Amaya, Amber, Ambrose, Amelia, Amelie, Amely, America, Americo, Amie, Amina, Amir, Amira, Amiya, Amos, Amparo, Amy, Amya, Ana, Anabel, Anabelle, Anahi, Anais, Anastacio, Anastasia, Anderson, Andre, Andreane, Andreanne, Andres, Andrew, Andy, Angel, Angela, Angelica, Angelina, Angeline, Angelita, Angelo, Angie, Angus, Anibal, Anika, Anissa, Anita, Aniya, Aniyah, Anjali, Anna, Annabel, Annabell, Annabelle, Annalise, Annamae, Annamarie, Anne, Annetta, Annette, Annie, Ansel, Ansley, Anthony, Antoinette, Antone, Antonetta, Antonette, Antonia, Antonietta, Antonina, Antonio, Antwan, Antwon, Anya, April, Ara, Araceli, Aracely, Arch, Archibald, Ardella, Arden, Ardith, Arely, Ari, Ariane, Arianna, Aric, Ariel, Arielle, Arjun, Arlene, Arlie, Arlo, Armand, Armando, Armani, Arnaldo, Arne, Arno, Arnold, Arnoldo, Arnulfo, Aron, Art, Arthur, Arturo, Arvel, Arvid, Arvilla, Aryanna, Asa, Asha, Ashlee, Ashleigh, Ashley, Ashly, Ashlynn, Ashton, Ashtyn, Asia, Assunta, Astrid, Athena, Aubree, Aubrey, Audie, Audra, Audreanne, Audrey, August, Augusta, Augustine, Augustus, Aurelia, Aurelie, Aurelio, Aurore, Austen, Austin, Austyn, Autumn, Ava, Avery, Avis, Axel, Ayana, Ayden, Ayla, Aylin, Baby, Bailee, Bailey, Barbara, Barney, Baron, Barrett, Barry, Bart, Bartholome, Barton, Baylee, Beatrice, Beau, Beaulah, Bell, Bella, Belle, Ben, Benedict, Benjamin, Bennett, Bennie, Benny, Benton, Berenice, Bernadette, Bernadine, Bernard, Bernardo, Berneice, Bernhard, Bernice, Bernie, Berniece, Bernita, Berry, Bert, Berta, Bertha, Bertram, Bertrand, Beryl, Bessie, Beth, Bethany, Bethel, Betsy, Bette, Bettie, Betty, Bettye, Beulah, Beverly, Bianka, Bill, Billie, Billy, Birdie, Blair, Blaise, Blake, Blanca, Blanche, Blaze, Bo, Bobbie, Bobby, Bonita, Bonnie, Boris, Boyd, Brad, Braden, Bradford, Bradley, Bradly, Brady, Braeden, Brain, Brandi, Brando, Brandon, Brandt, Brandy, Brandyn, Brannon, Branson, Brant, Braulio, Braxton, Brayan, Breana, Breanna, Breanne, Brenda, Brendan, Brenden, Brendon, Brenna, Brennan, Brennon, Brent, Bret, Brett, Bria, Brian, Briana, Brianne, Brice, Bridget, Bridgette, Bridie, Brielle, Brigitte, Brionna, Brisa, Britney, Brittany, Brock, Broderick, Brody, Brook, Brooke, Brooklyn, Brooks, Brown, Bruce, Bryana, Bryce, Brycen, Bryon, Buck, Bud, Buddy, Buford, Bulah, Burdette, Burley, Burnice, Buster, Cade, Caden, Caesar, Caitlyn, Cale, Caleb, Caleigh, Cali, Calista, Callie, Camden, Cameron, Camila, Camilla, Camille, Camren, Camron, Camryn, Camylle, Candace, Candelario, Candice, Candida, Candido, Cara, Carey, Carissa, Carlee, Carleton, Carley, Carli, Carlie, Carlo, Carlos, Carlotta, Carmel, Carmela, Carmella, Carmelo, Carmen, Carmine, Carol, Carolanne, Carole, Carolina, Caroline, Carolyn, Carolyne, Carrie, Carroll, Carson, Carter, Cary, Casandra, Casey, Casimer, Casimir, Casper, Cassandra, Cassandre, Cassidy, Cassie, Catalina, Caterina, Catharine, Catherine, Cathrine, Cathryn, Cathy, Cayla, Ceasar, Cecelia, Cecil, Cecile, Cecilia, Cedrick, Celestine, Celestino, Celia, Celine, Cesar, Chad, Chadd, Chadrick, Chaim, Chance, Chandler, Chanel, Chanelle, Charity, Charlene, Charles, Charley, Charlie, Charlotte, Chase, Chasity, Chauncey, Chaya, Chaz, Chelsea, Chelsey, Chelsie, Chesley, Chester, Chet, Cheyanne, Cheyenne, Chloe, Chris, Christ, Christa, Christelle, Christian, Christiana, Christina, Christine, Christop, Christophe, Christopher, Christy, Chyna, Ciara, Cicero, Cielo, Cierra, Cindy, Citlalli, Clair, Claire, Clara, Clarabelle, Clare, Clarissa, Clark, Claud, Claude, Claudia, Claudie, Claudine, Clay, Clemens, Clement, Clementina, Clementine, Clemmie, Cleo, Cleora, Cleta, Cletus, Cleve, Cleveland, Clifford, Clifton, Clint, Clinton, Clotilde, Clovis, Cloyd, Clyde, Coby, Cody, Colby, Cole, Coleman, Colin, Colleen, Collin, Colt, Colten, Colton, Columbus, Concepcion, Conner, Connie, Connor, Conor, Conrad, Constance, Constantin, Consuelo, Cooper, Cora, Coralie, Corbin, Cordelia, Cordell, Cordia, Cordie, Corene, Corine, Cornelius, Cornell, Corrine, Cortez, Cortney, Cory, Coty, Courtney, Coy, Craig, Crawford, Creola, Cristal, Cristian, Cristina, Cristobal, Cristopher, Cruz, Crystal, Crystel, Cullen, Curt, Curtis, Cydney, Cynthia, Cyril, Cyrus, Dagmar, Dahlia, Daija, Daisha, Daisy, Dakota, Dale, Dallas, Dallin, Dalton, Damaris, Dameon, Damian, Damien, Damion, Damon, Dan, Dana, Dandre, Dane, D'angelo, Dangelo, Danial, Daniela, Daniella, Danielle, Danika, Dannie, Danny, Dante, Danyka, Daphne, Daphnee, Daphney, Darby, Daren, Darian, Dariana, Darien, Dario, Darion, Darius, Darlene, Daron, Darrel, Darrell, Darren, Darrick, Darrin, Darrion, Darron, Darryl, Darwin, Daryl, Dashawn, Dasia, Dave, David, Davin, Davion, Davon, Davonte, Dawn, Dawson, Dax, Dayana, Dayna, Dayne, Dayton, Dean, Deangelo, Deanna, Deborah, Declan, Dedric, Dedrick, Dee, Deion, Deja, Dejah, Dejon, Dejuan, Delaney, Delbert, Delfina, Delia, Delilah, Dell, Della, Delmer, Delores, Delpha, Delphia, Delphine, Delta, Demarco, Demarcus, Demario, Demetris, Demetrius, Demond, Dena, Denis, Dennis, Deon, Deondre, Deontae, Deonte, Dereck, Derek, Derick, Deron, Derrick, Deshaun, Deshawn, Desiree, Desmond, Dessie, Destany, Destin, Destinee, Destiney, Destini, Destiny, Devan, Devante, Deven, Devin, Devon, Devonte, Devyn, Dewayne, Dewitt, Dexter, Diamond, Diana, Dianna, Diego, Dillan, Dillon, Dimitri, Dina, Dino, Dion, Dixie, Dock, Dolly, Dolores, Domenic, Domenica, Domenick, Domenico, Domingo, Dominic, Dominique, Don, Donald, Donato, Donavon, Donna, Donnell, Donnie, Donny, Dora, Dorcas, Dorian, Doris, Dorothea, Dorothy, Dorris, Dortha, Dorthy, Doug, Douglas, Dovie, Doyle, Drake, Drew, Duane, Dudley, Dulce, Duncan, Durward, Dustin, Dusty, Dwight, Dylan, Earl, Earlene, Earline, Earnest, Earnestine, Easter, Easton, Ebba, Ebony, Ed, Eda, Edd, Eddie, Eden, Edgar, Edgardo, Edison, Edmond, Edmund, Edna, Eduardo, Edward, Edwardo, Edwin, Edwina, Edyth, Edythe, Effie, Efrain, Efren, Eileen, Einar, Eino, Eladio, Elaina, Elbert, Elda, Eldon, Eldora, Eldred, Eldridge, Eleanora, Eleanore, Eleazar, Electa, Elena, Elenor, Elenora, Eleonore, Elfrieda, Eli, Elian, Eliane, Elias, Eliezer, Elijah, Elinor, Elinore, Elisa, Elisabeth, Elise, Eliseo, Elisha, Elissa, Eliza, Elizabeth, Ella, Ellen, Ellie, Elliot, Elliott, Ellis, Ellsworth, Elmer, Elmira, Elmo, Elmore, Elna, Elnora, Elody, Eloisa, Eloise, Elouise, Eloy, Elroy, Elsa, Else, Elsie, Elta, Elton, Elva, Elvera, Elvie, Elvis, Elwin, Elwyn, Elyse, Elyssa, Elza, Emanuel, Emelia, Emelie, Emely, Emerald, Emerson, Emery, Emie, Emil, Emile, Emilia, Emiliano, Emilie, Emilio, Emily, Emma, Emmalee, Emmanuel, Emmanuelle, Emmet, Emmett, Emmie, Emmitt, Emmy, Emory, Ena, Enid, Enoch, Enola, Enos, Enrico, Enrique, Ephraim, Era, Eriberto, Eric, Erica, Erich, Erick, Ericka, Erik, Erika, Erin, Erling, Erna, Ernest, Ernestina, Ernestine, Ernesto, Ernie, Ervin, Erwin, Eryn, Esmeralda, Esperanza, Esta, Esteban, Estefania, Estel, Estell, Estella, Estelle, Estevan, Esther, Estrella, Etha, Ethan, Ethel, Ethelyn, Ethyl, Ettie, Eudora, Eugene, Eugenia, Eula, Eulah, Eulalia, Euna, Eunice, Eusebio, Eva, Evalyn, Evan, Evangeline, Evans, Eve, Eveline, Evelyn, Everardo, Everett, Everette, Evert, Evie, Ewald, Ewell, Ezekiel, Ezequiel, Ezra, Fabian, Fabiola, Fae, Fannie, Fanny, Fatima, Faustino, Fausto, Favian, Fay, Faye, Federico, Felicia, Felicita, Felicity, Felipa, Felipe, Felix, Felton, Fermin, Fern, Fernando, Ferne, Fidel, Filiberto, Filomena, Finn, Fiona, Flavie, Flavio, Fleta, Fletcher, Flo, Florence, Florencio, Florian, Florida, Florine, Flossie, Floy, Floyd, Ford, Forest, Forrest, Foster, Frances, Francesca, Francesco, Francis, Francisca, Francisco, Franco, Frank, Frankie, Franz, Fred, Freda, Freddie, Freddy, Frederic, Frederick, Frederik, Frederique, Fredrick, Fredy, Freeda, Freeman, Freida, Frida, Frieda, Friedrich, Fritz, Furman, Gabe, Gabriel, Gabriella, Gabrielle, Gaetano, Gage, Gail, Gardner, Garett, Garfield, Garland, Garnet, Garnett, Garret, Garrett, Garrick, Garrison, Garry, Garth, Gaston, Gavin, Gay, Gayle, Gaylord, Gene, General, Genesis, Genevieve, Gennaro, Genoveva, Geo, Geoffrey, George, Georgette, Georgiana, Georgianna, Geovanni, Geovanny, Geovany, Gerald, Geraldine, Gerard, Gerardo, Gerda, Gerhard, Germaine, German, Gerry, Gerson, Gertrude, Gia, Gianni, Gideon, Gilbert, Gilberto, Gilda, Giles, Gillian, Gina, Gino, Giovani, Giovanna, Giovanni, Giovanny, Gisselle, Giuseppe, Gladyce, Gladys, Glen, Glenda, Glenna, Glennie, Gloria, Godfrey, Golda, Golden, Gonzalo, Gordon, Grace, Gracie, Graciela, Grady, Graham, Grant, Granville, Grayce, Grayson, Green, Greg, Gregg, Gregoria, Gregorio, Gregory, Greta, Gretchen, Greyson, Griffin, Grover, Guadalupe, Gudrun, Guido, Guillermo, Guiseppe, Gunnar, Gunner, Gus, Gussie, Gust, Gustave, Guy, Gwen, Gwendolyn, Hadley, Hailee, Hailey, Hailie, Hal, Haleigh, Haley, Halie, Halle, Hallie, Hank, Hanna, Hannah, Hans, Hardy, Harley, Harmon, Harmony, Harold, Harrison, Harry, Harvey, Haskell, Hassan, Hassie, Hattie, Haven, Hayden, Haylee, Hayley, Haylie, Hazel, Hazle, Heath, Heather, Heaven, Heber, Hector, Heidi, Helen, Helena, Helene, Helga, Hellen, Helmer, Heloise, Henderson, Henri, Henriette, Henry, Herbert, Herman, Hermann, Hermina, Herminia, Herminio, Hershel, Herta, Hertha, Hester, Hettie, Hilario, Hilbert, Hilda, Hildegard, Hillard, Hillary, Hilma, Hilton, Hipolito, Hiram, Hobart, Holden, Hollie, Hollis, Holly, Hope, Horace, Horacio, Hortense, Hosea, Houston, Howard, Howell, Hoyt, Hubert, Hudson, Hugh, Hulda, Humberto, Hunter, Hyman, Ian, Ibrahim, Icie, Ida, Idell, Idella, Ignacio, Ignatius, Ike, Ila, Ilene, Iliana, Ima, Imani, Imelda, Immanuel, Imogene, Ines, Irma, Irving, Irwin, Isaac, Isabel, Isabell, Isabella, Isabelle, Isac, Isadore, Isai, Isaiah, Isaias, Isidro, Ismael, Isobel, Isom, Israel, Issac, Itzel, Iva, Ivah, Ivory, Ivy, Izabella, Izaiah, Jabari, Jace, Jacey, Jacinthe, Jacinto, Jack, Jackeline, Jackie, Jacklyn, Jackson, Jacky, Jaclyn, Jacquelyn, Jacques, Jacynthe, Jada, Jade, Jaden, Jadon, Jadyn, Jaeden, Jaida, Jaiden, Jailyn, Jaime, Jairo, Jakayla, Jake, Jakob, Jaleel, Jalen, Jalon, Jalyn, Jamaal, Jamal, Jamar, Jamarcus, Jamel, Jameson, Jamey, Jamie, Jamil, Jamir, Jamison, Jammie, Jan, Jana, Janae, Jane, Janelle, Janessa, Janet, Janice, Janick, Janie, Janis, Janiya, Jannie, Jany, Jaquan, Jaquelin, Jaqueline, Jared, Jaren, Jarod, Jaron, Jarred, Jarrell, Jarret, Jarrett, Jarrod, Jarvis, Jasen, Jasmin, Jason, Jasper, Jaunita, Javier, Javon, Javonte, Jay, Jayce, Jaycee, Jayda, Jayde, Jayden, Jaydon, Jaylan, Jaylen, Jaylin, Jaylon, Jayme, Jayne, Jayson, Jazlyn, Jazmin, Jazmyn, Jazmyne, Jean, Jeanette, Jeanie, Jeanne, Jed, Jedediah, Jedidiah, Jeff, Jefferey, Jeffery, Jeffrey, Jeffry, Jena, Jenifer, Jennie, Jennifer, Jennings, Jennyfer, Jensen, Jerad, Jerald, Jeramie, Jeramy, Jerel, Jeremie, Jeremy, Jermain, Jermaine, Jermey, Jerod, Jerome, Jeromy, Jerrell, Jerrod, Jerrold, Jerry, Jess, Jesse, Jessica, Jessie, Jessika, Jessy, Jessyca, Jesus, Jett, Jettie, Jevon, Jewel, Jewell, Jillian, Jimmie, Jimmy, Jo, Joan, Joana, Joanie, Joanne, Joannie, Joanny, Joany, Joaquin, Jocelyn, Jodie, Jody, Joe, Joel, Joelle, Joesph, Joey, Johan, Johann, Johanna, Johathan, John, Johnathan, Johnathon, Johnnie, Johnny, Johnpaul, Johnson, Jolie, Jon, Jonas, Jonatan, Jonathan, Jonathon, Jordan, Jordane, Jordi, Jordon, Jordy, Jordyn, Jorge, Jose, Josefa, Josefina, Joseph, Josephine, Josh, Joshua, Joshuah, Josiah, Josiane, Josianne, Josie, Josue, Jovan, Jovani, Jovanny, Jovany, Joy, Joyce, Juana, Juanita, Judah, Judd, Jude, Judge, Judson, Judy, Jules, Julia, Julian, Juliana, Julianne, Julie, Julien, Juliet, Julio, Julius, June, Junior, Junius, Justen, Justice, Justina, Justine, Juston, Justus, Justyn, Juvenal, Juwan, Kacey, Kaci, Kacie, Kade, Kaden, Kadin, Kaela, Kaelyn, Kaia, Kailee, Kailey, Kailyn, Kaitlin, Kaitlyn, Kale, Kaleb, Kaleigh, Kaley, Kali, Kallie, Kameron, Kamille, Kamren, Kamron, Kamryn, Kane, Kara, Kareem, Karelle, Karen, Kari, Kariane, Karianne, Karina, Karine, Karl, Karlee, Karley, Karli, Karlie, Karolann, Karson, Kasandra, Kasey, Kassandra, Katarina, Katelin, Katelyn, Katelynn, Katharina, Katherine, Katheryn, Kathleen, Kathlyn, Kathryn, Kathryne, Katlyn, Katlynn, Katrina, Katrine, Kattie, Kavon, Kay, Kaya, Kaycee, Kayden, Kayla, Kaylah, Kaylee, Kayleigh, Kayley, Kayli, Kaylie, Kaylin, Keagan, Keanu, Keara, Keaton, Keegan, Keeley, Keely, Keenan, Keira, Keith, Kellen, Kelley, Kelli, Kellie, Kelly, Kelsi, Kelsie, Kelton, Kelvin, Ken, Kendall, Kendra, Kendrick, Kenna, Kennedi, Kennedy, Kenneth, Kennith, Kenny, Kenton, Kenya, Kenyatta, Kenyon, Keon, Keshaun, Keshawn, Keven, Kevin, Kevon, Keyon, Keyshawn, Khalid, Khalil, Kian, Kiana, Kianna, Kiara, Kiarra, Kiel, Kiera, Kieran, Kiley, Kim, Kimberly, King, Kip, Kira, Kirk, Kirsten, Kirstin, Kitty, Kobe, Koby, Kody, Kolby, Kole, Korbin, Korey, Kory, Kraig, Kris, Krista, Kristian, Kristin, Kristina, Kristofer, Kristoffer, Kristopher, Kristy, Krystal, Krystel, Krystina, Kurt, Kurtis, Kyla, Kyle, Kylee, Kyleigh, Kyler, Kylie, Kyra, Lacey, Lacy, Ladarius, Lafayette, Laila, Laisha, Lamar, Lambert, Lamont, Lance, Landen, Lane, Laney, Larissa, Laron, Larry, Larue, Laura, Laurel, Lauren, Laurence, Lauretta, Lauriane, Laurianne, Laurie, Laurine, Laury, Lauryn, Lavada, Lavern, Laverna, Laverne, Lavina, Lavinia, Lavon, Lavonne, Lawrence, Lawson, Layla, Layne, Lazaro, Lea, Leann, Leanna, Leanne, Leatha, Leda, Lee, Leif, Leila, Leilani, Lela, Lelah, Leland, Lelia, Lempi, Lemuel, Lenna, Lennie, Lenny, Lenora, Lenore, Leo, Leola, Leon, Leonard, Leonardo, Leone, Leonel, Leonie, Leonor, Leonora, Leopold, Leopoldo, Leora, Lera, Lesley, Leslie, Lesly, Lessie, Lester, Leta, Letha, Letitia, Levi, Lew, Lewis, Lexi, Lexie, Lexus, Lia, Liam, Liana, Libbie, Libby, Lila, Lilian, Liliana, Liliane, Lilla, Lillian, Lilliana, Lillie, Lilly, Lily, Lilyan, Lina, Lincoln, Linda, Lindsay, Lindsey, Linnea, Linnie, Linwood, Lionel, Lisa, Lisandro, Lisette, Litzy, Liza, Lizeth, Lizzie, Llewellyn, Lloyd, Logan, Lois, Lola, Lolita, Loma, Lon, London, Lonie, Lonnie, Lonny, Lonzo, Lora, Loraine, Loren, Lorena, Lorenz, Lorenza, Lorenzo, Lori, Lorine, Lorna, Lottie, Lou, Louie, Louisa, Lourdes, Louvenia, Lowell, Loy, Loyal, Loyce, Lucas, Luciano, Lucie, Lucienne, Lucile, Lucinda, Lucio, Lucious, Lucius, Lucy, Ludie, Ludwig, Lue, Luella, Luigi, Luis, Luisa, Lukas, Lula, Lulu, Luna, Lupe, Lura, Lurline, Luther, Luz, Lyda, Lydia, Lyla, Lynn, Lyric, Lysanne, Mabel, Mabelle, Mable, Mac, Macey, Maci, Macie, Mack, Mackenzie, Macy, Madaline, Madalyn, Maddison, Madeline, Madelyn, Madelynn, Madge, Madie, Madilyn, Madisen, Madison, Madisyn, Madonna, Madyson, Mae, Maegan, Maeve, Mafalda, Magali, Magdalen, Magdalena, Maggie, Magnolia, Magnus, Maia, Maida, Maiya, Major, Makayla, Makenna, Makenzie, Malachi, Malcolm, Malika, Malinda, Mallie, Mallory, Malvina, Mandy, Manley, Manuel, Manuela, Mara, Marc, Marcel, Marcelina, Marcelino, Marcella, Marcelle, Marcellus, Marcelo, Marcia, Marco, Marcos, Marcus, Margaret, Margarete, Margarett, Margaretta, Margarette, Margarita, Marge, Margie, Margot, Margret, Marguerite, Maria, Mariah, Mariam, Marian, Mariana, Mariane, Marianna, Marianne, Mariano, Maribel, Marie, Mariela, Marielle, Marietta, Marilie, Marilou, Marilyne, Marina, Mario, Marion, Marisa, Marisol, Maritza, Marjolaine, Marjorie, Marjory, Mark, Markus, Marlee, Marlen, Marlene, Marley, Marlin, Marlon, Marques, Marquis, Marquise, Marshall, Marta, Martin, Martina, Martine, Marty, Marvin, Mary, Maryam, Maryjane, Maryse, Mason, Mateo, Mathew, Mathias, Mathilde, Matilda, Matilde, Matt, Matteo, Mattie, Maud, Maude, Maudie, Maureen, Maurice, Mauricio, Maurine, Maverick, Mavis, Max, Maxie, Maxime, Maximilian, Maximillia, Maximillian, Maximo, Maximus, Maxine, Maxwell, May, Maya, Maybell, Maybelle, Maye, Maymie, Maynard, Mayra, Mazie, Mckayla, Mckenna, Mckenzie, Meagan, Meaghan, Meda, Megane, Meggie, Meghan, Mekhi, Melany, Melba, Melisa, Melissa, Mellie, Melody, Melvin, Melvina, Melyna, Melyssa, Mercedes, Meredith, Merl, Merle, Merlin, Merritt, Mertie, Mervin, Meta, Mia, Micaela, Micah, Michael, Michaela, Michale, Micheal, Michel, Michele, Michelle, Miguel, Mikayla, Mike, Mikel, Milan, Miles, Milford, Miller, Millie, Milo, Milton, Mina, Minerva, Minnie, Miracle, Mireille, Mireya, Misael, Missouri, Misty, Mitchel, Mitchell, Mittie, Modesta, Modesto, Mohamed, Mohammad, Mohammed, Moises, Mollie, Molly, Mona, Monica, Monique, Monroe, Monserrat, Monserrate, Montana, Monte, Monty, Morgan, Moriah, Morris, Mortimer, Morton, Mose, Moses, Moshe, Mossie, Mozell, Mozelle, Muhammad, Muriel, Murl, Murphy, Murray, Mustafa, Mya, Myah, Mylene, Myles, Myra, Myriam, Myrl, Myrna, Myron, Myrtice, Myrtie, Myrtis, Myrtle, Nadia, Nakia, Name, Nannie, Naomi, Naomie, Napoleon, Narciso, Nash, Nasir, Nat, Natalia, Natalie, Natasha, Nathan, Nathanael, Nathanial, Nathaniel, Nathen, Nayeli, Neal, Ned, Nedra, Neha, Neil, Nelda, Nella, Nelle, Nellie, Nels, Nelson, Neoma, Nestor, Nettie, Neva, Newell, Newton, Nia, Nicholas, Nicholaus, Nichole, Nick, Nicklaus, Nickolas, Nico, Nicola, Nicolas, Nicole, Nicolette, Nigel, Nikita, Nikki, Nikko, Niko, Nikolas, Nils, Nina, Noah, Noble, Noe, Noel, Noelia, Noemi, Noemie, Noemy, Nola, Nolan, Nona, Nora, Norbert, Norberto, Norene, Norma, Norris, Norval, Norwood, Nova, Novella, Nya, Nyah, Nyasia, Obie, Oceane, Ocie, Octavia, Oda, Odell, Odessa, Odie, Ofelia, Okey, Ola, Olaf, Ole, Olen, Oleta, Olga, Olin, Oliver, Ollie, Oma, Omari, Omer, Ona, Onie, Opal, Ophelia, Ora, Oral, Oran, Oren, Orie, Orin, Orion, Orland, Orlando, Orlo, Orpha, Orrin, Orval, Orville, Osbaldo, Osborne, Oscar, Osvaldo, Oswald, Oswaldo, Otha, Otho, Otilia, Otis, Ottilie, Ottis, Otto, Ova, Owen, Ozella, Ozzie, Pablo, Paige, Palma, Pamela, Pansy, Paolo, Paris, Parker, Pascale, Pasquale, Pat, Patience, Patricia, Patrick, Patsy, Pattie, Paul, Paula, Pauline, Paxton, Payton, Pearl, Pearlie, Pearline, Pedro, Peggie, Penelope, Percival, Percy, Perry, Pete, Peter, Petra, Peyton, Philip, Phoebe, Phyllis, Pierce, Pierre, Pietro, Pink, Pinkie, Piper, Polly, Porter, Precious, Presley, Preston, Price, Prince, Princess, Priscilla, Providenci, Prudence, Queen, Queenie, Quentin, Quincy, Quinn, Quinten, Quinton, Rachael, Rachel, Rachelle, Rae, Raegan, Rafael, Rafaela, Raheem, Rahsaan, Rahul, Raina, Raleigh, Ralph, Ramiro, Ramon, Ramona, Randal, Randall, Randi, Randy, Ransom, Raoul, Raphael, Raphaelle, Raquel, Rashad, Rashawn, Rasheed, Raul, Raven, Ray, Raymond, Raymundo, Reagan, Reanna, Reba, Rebeca, Rebecca, Rebeka, Rebekah, Reece, Reed, Reese, Regan, Reggie, Reginald, Reid, Reilly, Reina, Reinhold, Remington, Rene, Renee, Ressie, Reta, Retha, Retta, Reuben, Reva, Rex, Rey, Reyes, Reymundo, Reyna, Reynold, Rhea, Rhett, Rhianna, Rhiannon, Rhoda, Ricardo, Richard, Richie, Richmond, Rick, Rickey, Rickie, Ricky, Rico, Rigoberto, Riley, Rita, River, Robb, Robbie, Robert, Roberta, Roberto, Robin, Robyn, Rocio, Rocky, Rod, Roderick, Rodger, Rodolfo, Rodrick, Rodrigo, Roel, Rogelio, Roger, Rogers, Rolando, Rollin, Roma, Romaine, Roman, Ron, Ronaldo, Ronny, Roosevelt, Rory, Rosa, Rosalee, Rosalia, Rosalind, Rosalinda, Rosalyn, Rosamond, Rosanna, Rosario, Roscoe, Rose, Rosella, Roselyn, Rosemarie, Rosemary, Rosendo, Rosetta, Rosie, Rosina, Roslyn, Ross, Rossie, Rowan, Rowena, Rowland, Roxane, Roxanne, Roy, Royal, Royce, Rozella, Ruben, Rubie, Ruby, Rubye, Rudolph, Rudy, Rupert, Russ, Russel, Russell, Rusty, Ruth, Ruthe, Ruthie, Ryan, Ryann, Ryder, Rylan, Rylee, Ryleigh, Ryley, Sabina, Sabrina, Sabryna, Sadie, Sadye, Sage, Saige, Sallie, Sally, Salma, Salvador, Salvatore, Sam, Samanta, Samantha, Samara, Samir, Sammie, Sammy, Samson, Sandra, Sandrine, Sandy, Sanford, Santa, Santiago, Santina, Santino, Santos, Sarah, Sarai, Sarina, Sasha, Saul, Savanah, Savanna, Savannah, Savion, Scarlett, Schuyler, Scot, Scottie, Scotty, Seamus, Sean, Sebastian, Sedrick, Selena, Selina, Selmer, Serena, Serenity, Seth, Shad, Shaina, Shakira, Shana, Shane, Shanel, Shanelle, Shania, Shanie, Shaniya, Shanna, Shannon, Shanny, Shanon, Shany, Sharon, Shaun, Shawn, Shawna, Shaylee, Shayna, Shayne, Shea, Sheila, Sheldon, Shemar, Sheridan, Sherman, Sherwood, Shirley, Shyann, Shyanne, Sibyl, Sid, Sidney, Sienna, Sierra, Sigmund, Sigrid, Sigurd, Silas, Sim, Simeon, Simone, Sincere, Sister, Skye, Skyla, Skylar, Sofia, Soledad, Solon, Sonia, Sonny, Sonya, Sophia, Sophie, Spencer, Stacey, Stacy, Stan, Stanford, Stanley, Stanton, Stefan, Stefanie, Stella, Stephan, Stephania, Stephanie, Stephany, Stephen, Stephon, Sterling, Steve, Stevie, Stewart, Stone, Stuart, Summer, Sunny, Susan, Susana, Susanna, Susie, Suzanne, Sven, Syble, Sydnee, Sydney, Sydni, Sydnie, Sylvan, Sylvester, Sylvia, Tabitha, Tad, Talia, Talon, Tamara, Tamia, Tania, Tanner, Tanya, Tara, Taryn, Tate, Tatum, Tatyana, Taurean, Tavares, Taya, Taylor, Teagan, Ted, Telly, Terence, Teresa, Terrance, Terrell, Terrence, Terrill, Terry, Tess, Tessie, Tevin, Thad, Thaddeus, Thalia, Thea, Thelma, Theo, Theodora, Theodore, Theresa, Therese, Theresia, Theron, Thomas, Thora, Thurman, Tia, Tiana, Tianna, Tiara, Tierra, Tiffany, Tillman, Timmothy, Timmy, Timothy, Tina, Tito, Titus, Tobin, Toby, Tod, Tom, Tomas, Tomasa, Tommie, Toney, Toni, Tony, Torey, Torrance, Torrey, Toy, Trace, Tracey, Tracy, Travis, Travon, Tre, Tremaine, Tremayne, Trent, Trenton, Tressa, Tressie, Treva, Trever, Trevion, Trevor, Trey, Trinity, Trisha, Tristian, Tristin, Triston, Troy, Trudie, Trycia, Trystan, Turner, Twila, Tyler, Tyra, Tyree, Tyreek, Tyrel, Tyrell, Tyrese, Tyrique, Tyshawn, Tyson, Ubaldo, Ulices, Ulises, Una, Unique, Urban, Uriah, Uriel, Ursula, Vada, Valentin, Valentina, Valentine, Valerie, Vallie, Van, Vance, Vanessa, Vaughn, Veda, Velda, Vella, Velma, Velva, Vena, Verda, Verdie, Vergie, Verla, Verlie, Vern, Verna, Verner, Vernice, Vernie, Vernon, Verona, Veronica, Vesta, Vicenta, Vicente, Vickie, Vicky, Victor, Victoria, Vida, Vidal, Vilma, Vince, Vincent, Vincenza, Vincenzo, Vinnie, Viola, Violet, Violette, Virgie, Virgil, Virginia, Virginie, Vita, Vito, Viva, Vivian, Viviane, Vivianne, Vivien, Vivienne, Vladimir, Wade, Waino, Waldo, Walker, Wallace, Walter, Walton, Wanda, Ward, Warren, Watson, Wava, Waylon, Wayne, Webster, Weldon, Wellington, Wendell, Wendy, Werner, Westley, Weston, Whitney, Wilber, Wilbert, Wilburn, Wiley, Wilford, Wilfred, Wilfredo, Wilfrid, Wilhelm, Wilhelmine, Will, Willa, Willard, William, Willie, Willis, Willow, Willy, Wilma, Wilmer, Wilson, Wilton, Winfield, Winifred, Winnifred, Winona, Winston, Woodrow, Wyatt, Wyman, Xander, Xavier, Xzavier, Yadira, Yasmeen, Yasmin, Yasmine, Yazmin, Yesenia, Yessenia, Yolanda, Yoshiko, Yvette, Yvonne, Zachariah, Zachary, Zachery, Zack, Zackary, Zackery, Zakary, Zander, Zane, Zaria, Zechariah, Zelda, Zella, Zelma, Zena, Zetta, Zion, Zita, Zoe, Zoey, Zoie, Zoila, Zola, Zora, Zula]
|
9
|
+
last_name: [Abbott, Abernathy, Abshire, Adams, Altenwerth, Anderson, Ankunding, Armstrong, Auer, Aufderhar, Bahringer, Bailey, Balistreri, Barrows, Bartell, Bartoletti, Barton, Bashirian, Batz, Bauch, Baumbach, Bayer, Beahan, Beatty, Bechtelar, Becker, Bednar, Beer, Beier, Berge, Bergnaum, Bergstrom, Bernhard, Bernier, Bins, Blanda, Blick, Block, Bode, Boehm, Bogan, Bogisich, Borer, Bosco, Botsford, Boyer, Boyle, Bradtke, Brakus, Braun, Breitenberg, Brekke, Brown, Bruen, Buckridge, Carroll, Carter, Cartwright, Casper, Cassin, Champlin, Christiansen, Cole, Collier, Collins, Conn, Connelly, Conroy, Considine, Corkery, Cormier, Corwin, Cremin, Crist, Crona, Cronin, Crooks, Cruickshank, Cummerata, Cummings, Dach, D'Amore, Daniel, Dare, Daugherty, Davis, Deckow, Denesik, Dibbert, Dickens, Dicki, Dickinson, Dietrich, Donnelly, Dooley, Douglas, Doyle, DuBuque, Durgan, Ebert, Effertz, Eichmann, Emard, Emmerich, Erdman, Ernser, Fadel, Fahey, Farrell, Fay, Feeney, Feest, Feil, Ferry, Fisher, Flatley, Frami, Franecki, Friesen, Fritsch, Funk, Gaylord, Gerhold, Gerlach, Gibson, Gislason, Gleason, Gleichner, Glover, Goldner, Goodwin, Gorczany, Gottlieb, Goyette, Grady, Graham, Grant, Green, Greenfelder, Greenholt, Grimes, Gulgowski, Gusikowski, Gutkowski, Gutmann, Haag, Hackett, Hagenes, Hahn, Haley, Halvorson, Hamill, Hammes, Hand, Hane, Hansen, Harber, Harris, Hartmann, Harvey, Hauck, Hayes, Heaney, Heathcote, Hegmann, Heidenreich, Heller, Herman, Hermann, Hermiston, Herzog, Hessel, Hettinger, Hickle, Hilll, Hills, Hilpert, Hintz, Hirthe, Hodkiewicz, Hoeger, Homenick, Hoppe, Howe, Howell, Hudson, Huel, Huels, Hyatt, Jacobi, Jacobs, Jacobson, Jakubowski, Jaskolski, Jast, Jenkins, Jerde, Johns, Johnson, Johnston, Jones, Kassulke, Kautzer, Keebler, Keeling, Kemmer, Kerluke, Kertzmann, Kessler, Kiehn, Kihn, Kilback, King, Kirlin, Klein, Kling, Klocko, Koch, Koelpin, Koepp, Kohler, Konopelski, Koss, Kovacek, Kozey, Krajcik, Kreiger, Kris, Kshlerin, Kub, Kuhic, Kuhlman, Kuhn, Kulas, Kunde, Kunze, Kuphal, Kutch, Kuvalis, Labadie, Lakin, Lang, Langosh, Langworth, Larkin, Larson, Leannon, Lebsack, Ledner, Leffler, Legros, Lehner, Lemke, Lesch, Leuschke, Lind, Lindgren, Littel, Little, Lockman, Lowe, Lubowitz, Lueilwitz, Luettgen, Lynch, Macejkovic, MacGyver, Maggio, Mann, Mante, Marks, Marquardt, Marvin, Mayer, Mayert, McClure, McCullough, McDermott, McGlynn, McKenzie, McLaughlin, Medhurst, Mertz, Metz, Miller, Mills, Mitchell, Moen, Mohr, Monahan, Moore, Morar, Morissette, Mosciski, Mraz, Mueller, Muller, Murazik, Murphy, Murray, Nader, Nicolas, Nienow, Nikolaus, Nitzsche, Nolan, Oberbrunner, O'Connell, O'Conner, O'Hara, O'Keefe, O'Kon, Okuneva, Olson, Ondricka, O'Reilly, Orn, Ortiz, Osinski, Pacocha, Padberg, Pagac, Parisian, Parker, Paucek, Pfannerstill, Pfeffer, Pollich, Pouros, Powlowski, Predovic, Price, Prohaska, Prosacco, Purdy, Quigley, Quitzon, Rath, Ratke, Rau, Raynor, Reichel, Reichert, Reilly, Reinger, Rempel, Renner, Reynolds, Rice, Rippin, Ritchie, Robel, Roberts, Rodriguez, Rogahn, Rohan, Rolfson, Romaguera, Roob, Rosenbaum, Rowe, Ruecker, Runolfsdottir, Runolfsson, Runte, Russel, Rutherford, Ryan, Sanford, Satterfield, Sauer, Sawayn, Schaden, Schaefer, Schamberger, Schiller, Schimmel, Schinner, Schmeler, Schmidt, Schmitt, Schneider, Schoen, Schowalter, Schroeder, Schulist, Schultz, Schumm, Schuppe, Schuster, Senger, Shanahan, Shields, Simonis, Sipes, Skiles, Smith, Smitham, Spencer, Spinka, Sporer, Stamm, Stanton, Stark, Stehr, Steuber, Stiedemann, Stokes, Stoltenberg, Stracke, Streich, Stroman, Strosin, Swaniawski, Swift, Terry, Thiel, Thompson, Tillman, Torp, Torphy, Towne, Toy, Trantow, Tremblay, Treutel, Tromp, Turcotte, Turner, Ullrich, Upton, Vandervort, Veum, Volkman, Von, VonRueden, Waelchi, Walker, Walsh, Walter, Ward, Waters, Watsica, Weber, Wehner, Weimann, Weissnat, Welch, West, White, Wiegand, Wilderman, Wilkinson, Will, Williamson, Willms, Windler, Wintheiser, Wisoky, Wisozk, Witting, Wiza, Wolf, Wolff, Wuckert, Wunsch, Wyman, Yost, Yundt, Zboncak, Zemlak, Ziemann, Zieme, Zulauf]
|
10
|
+
number:
|
11
|
+
- "777"
|
12
|
+
- "69"
|
13
|
+
- "34"
|
14
|
+
- "{number}4"
|
15
|
+
domain:
|
16
|
+
- "{noun}{tld}"
|
17
|
+
- "{noun}{noun}{tld}"
|
18
|
+
noun:
|
19
|
+
- abc
|
20
|
+
- acorn
|
21
|
+
- adze
|
22
|
+
- aphx
|
23
|
+
- bat
|
24
|
+
- ball
|
25
|
+
- beach
|
26
|
+
- bell
|
27
|
+
- cat
|
28
|
+
- chalk
|
29
|
+
- dog
|
30
|
+
- dent
|
31
|
+
- elp
|
32
|
+
tld:
|
33
|
+
- .com
|
34
|
+
- .com.au
|
35
|
+
- .co
|
36
|
+
- .co.nz
|
37
|
+
- .org
|
38
|
+
- .info
|
39
|
+
- .co.uk
|
40
|
+
- .tech
|
41
|
+
- .io
|
42
|
+
- .xyz
|
data/lib/calyx/errors.rb
CHANGED
@@ -1,11 +1,58 @@
|
|
1
1
|
module Calyx
|
2
|
+
# Library-specific error types.
|
2
3
|
module Errors
|
3
|
-
|
4
|
+
# Only rules that exist in the registry can be evaluated. When a
|
5
|
+
# non-existent rule is referenced, this error is raised.
|
6
|
+
#
|
7
|
+
# grammar = Calyx::Grammar.new do
|
8
|
+
# start :blank
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# grammar.evaluate
|
12
|
+
# # => Calyx::Errors::MissingRule: :blank is not registered
|
13
|
+
class MissingRule < RuntimeError;
|
14
|
+
def initialize(msg)
|
15
|
+
super(":#{msg} is not registered")
|
16
|
+
end
|
17
|
+
end
|
4
18
|
|
5
|
-
|
6
|
-
|
7
|
-
|
19
|
+
# Raised when a rule passed in via a context map conflicts with an existing
|
20
|
+
# rule in the grammar.
|
21
|
+
#
|
22
|
+
# grammar = Calyx::Grammar.new do
|
23
|
+
# start :priority
|
24
|
+
# priority "(A)"
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# grammar.evaluate(priority: "(B)")
|
28
|
+
# # => Calyx::Errors::DuplicateRule: :priority is already registered
|
29
|
+
class DuplicateRule < ArgumentError
|
30
|
+
def initialize(msg)
|
31
|
+
super(":#{msg} is already registered")
|
8
32
|
end
|
9
33
|
end
|
34
|
+
|
35
|
+
# Raised when the client attempts to load a grammar with an unsupported file
|
36
|
+
# extension. Only `.json` and `.yml` are valid.
|
37
|
+
#
|
38
|
+
# Calyx::Grammar.load("grammar.toml")
|
39
|
+
# # => Calyx::Errors::UnsupportedFormat: grammar.toml is not a valid JSON or YAML file
|
40
|
+
class UnsupportedFormat < ArgumentError
|
41
|
+
def initialize(msg)
|
42
|
+
super("#{File.basename(msg)} is not a valid JSON or YAML file")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Raised when a rule defined in a grammar is invalid. This will prevent
|
47
|
+
# the grammar from compiling correctly.
|
48
|
+
#
|
49
|
+
# Calyx::Grammar.new do
|
50
|
+
# start '40%' => 0.4, '30%' => 0.3
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# # => Calyx::Errors::InvalidDefinition: Weights must sum to 1
|
54
|
+
#
|
55
|
+
class InvalidDefinition < ArgumentError
|
56
|
+
end
|
10
57
|
end
|
11
58
|
end
|
data/lib/calyx/format.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
module Calyx
|
2
|
+
# Helper methods for loading and initializing grammars from static files
|
3
|
+
# on disk.
|
2
4
|
module Format
|
5
|
+
# Reads a file and parses its format, based on the given extension.
|
6
|
+
#
|
7
|
+
# Accepts a JSON or YAML file path, identified by its extension (`.json`
|
8
|
+
# or `.yml`).
|
9
|
+
#
|
10
|
+
# @param filename [String]
|
11
|
+
# @return [Calyx::Grammar]
|
3
12
|
def self.load(filename)
|
4
13
|
file = File.read(filename)
|
5
14
|
extension = File.extname(filename)
|
@@ -8,20 +17,26 @@ module Calyx
|
|
8
17
|
elsif extension == ".json"
|
9
18
|
self.load_json(file)
|
10
19
|
else
|
11
|
-
raise
|
20
|
+
raise Errors::UnsupportedFormat.new(filename)
|
12
21
|
end
|
13
22
|
end
|
14
23
|
|
15
|
-
|
24
|
+
# Converts the given string of YAML data to a grammar instance.
|
25
|
+
#
|
26
|
+
# @param data [String]
|
27
|
+
# @return [Calyx::Grammar]
|
28
|
+
def self.load_yml(data)
|
16
29
|
require 'yaml'
|
17
|
-
|
18
|
-
self.build_grammar(yaml)
|
30
|
+
self.build_grammar(YAML.load(data))
|
19
31
|
end
|
20
32
|
|
21
|
-
|
33
|
+
# Converts the given string of JSON data to a grammar instance.
|
34
|
+
#
|
35
|
+
# @param data [String]
|
36
|
+
# @return [Calyx::Grammar]
|
37
|
+
def self.load_json(data)
|
22
38
|
require 'json'
|
23
|
-
|
24
|
-
self.build_grammar(json)
|
39
|
+
self.build_grammar(JSON.parse(data))
|
25
40
|
end
|
26
41
|
|
27
42
|
private
|
data/lib/calyx/grammar.rb
CHANGED
@@ -1,43 +1,104 @@
|
|
1
1
|
module Calyx
|
2
|
+
# The main public interface to Calyx. Grammars represent the concept of a
|
3
|
+
# template grammar defined by a set of production rules that can be chained
|
4
|
+
# and nested from a given starting rule.
|
5
|
+
#
|
6
|
+
# Calyx works like a traditional phrase-structured grammar in reverse. Instead
|
7
|
+
# of recognising strings based on a union of possible matches, it generates
|
8
|
+
# strings by representing the union as a choice and randomly picking one
|
9
|
+
# of the options each time the grammar runs.
|
2
10
|
class Grammar
|
3
11
|
class << self
|
12
|
+
# Access the registry belonging to this grammar class.
|
13
|
+
#
|
14
|
+
# Constructs a new registry if it isn't already available.
|
15
|
+
#
|
16
|
+
# @return [Calyx::Registry]
|
4
17
|
def registry
|
5
18
|
@registry ||= Registry.new
|
6
19
|
end
|
7
20
|
|
21
|
+
# Load a grammar instance from the given file.
|
22
|
+
#
|
23
|
+
# Accepts a JSON or YAML file path, identified by its extension (`.json`
|
24
|
+
# or `.yml`).
|
25
|
+
#
|
26
|
+
# @param filename [String]
|
27
|
+
# @return [Calyx::Grammar]
|
8
28
|
def load(filename)
|
9
29
|
Format.load(filename)
|
10
30
|
end
|
11
31
|
|
12
|
-
|
13
|
-
|
32
|
+
# DSL helper method for registering a modifier module with the grammar.
|
33
|
+
#
|
34
|
+
# @param module_name [Module]
|
35
|
+
def modifier(module_name)
|
36
|
+
registry.modifier(module_name)
|
14
37
|
end
|
15
38
|
|
39
|
+
# DSL helper method for registering a paired mapping regex.
|
40
|
+
#
|
41
|
+
# @param name [Symbol]
|
42
|
+
# @param pairs [Hash<Regex,String>]
|
16
43
|
def mapping(name, pairs)
|
17
44
|
registry.mapping(name, pairs)
|
18
45
|
end
|
19
46
|
|
47
|
+
# DSL helper method for registering the given block as a string filter.
|
48
|
+
#
|
49
|
+
# @param name [Symbol]
|
50
|
+
# @block block with a single string argument returning a modified string.
|
20
51
|
def filter(name, &block)
|
21
52
|
registry.mapping(name, &block)
|
22
53
|
end
|
23
54
|
|
55
|
+
# DSL helper method for registering a new grammar rule.
|
56
|
+
#
|
57
|
+
# Not usually used directly, as the method missing API is less verbose.
|
58
|
+
#
|
59
|
+
# @param name [Symbol]
|
60
|
+
# @param productions [Array]
|
24
61
|
def rule(name, *productions)
|
25
62
|
registry.rule(name, *productions)
|
26
63
|
end
|
27
64
|
|
65
|
+
# Augument the grammar with a method missing hook that treats class
|
66
|
+
# method calls as declarations of a new rule.
|
67
|
+
#
|
68
|
+
# This must be bypassed by calling `#rule` directly if the name of the
|
69
|
+
# desired rule clashes with an existing helper method.
|
70
|
+
#
|
71
|
+
# @param name [Symbol]
|
72
|
+
# @param productions [Array]
|
28
73
|
def method_missing(name, *productions)
|
29
74
|
registry.rule(name, *productions)
|
30
75
|
end
|
31
76
|
|
77
|
+
# Hook for combining the registry of a parent grammar into the child that
|
78
|
+
# inherits from it.
|
79
|
+
#
|
80
|
+
# @param child_registry [Calyx::Registry]
|
32
81
|
def inherit_registry(child_registry)
|
33
82
|
registry.combine(child_registry) unless child_registry.nil?
|
34
83
|
end
|
35
84
|
|
85
|
+
# Hook for combining the rules from a parent grammar into the child that
|
86
|
+
# inherits from it.
|
87
|
+
#
|
88
|
+
# This is automatically called by the Ruby engine.
|
89
|
+
#
|
90
|
+
# @param subclass [Class]
|
36
91
|
def inherited(subclass)
|
37
92
|
subclass.inherit_registry(registry)
|
38
93
|
end
|
39
94
|
end
|
40
95
|
|
96
|
+
# Create a new grammar instance, passing in a random seed if needed.
|
97
|
+
#
|
98
|
+
# Grammar rules can be constructed on the fly when the passed-in block is
|
99
|
+
# evaluated.
|
100
|
+
#
|
101
|
+
# @param seed [Number]
|
41
102
|
def initialize(seed=nil, &block)
|
42
103
|
@seed = seed || Random.new_seed
|
43
104
|
srand(@seed)
|
@@ -50,6 +111,11 @@ module Calyx
|
|
50
111
|
end
|
51
112
|
end
|
52
113
|
|
114
|
+
# Produces a string as an output of the grammar.
|
115
|
+
#
|
116
|
+
# @param start_symbol [Symbol]
|
117
|
+
# @param rules_map [Hash]
|
118
|
+
# @return [String]
|
53
119
|
def generate(*args)
|
54
120
|
start_symbol, rules_map = map_default_args(*args)
|
55
121
|
|
@@ -58,6 +124,11 @@ module Calyx
|
|
58
124
|
end.join(''.freeze)
|
59
125
|
end
|
60
126
|
|
127
|
+
# Produces a syntax tree of nested list nodes as an output of the grammar.
|
128
|
+
#
|
129
|
+
# @param start_symbol [Symbol]
|
130
|
+
# @param rules_map [Hash]
|
131
|
+
# @return [Array]
|
61
132
|
def evaluate(*args)
|
62
133
|
start_symbol, rules_map = map_default_args(*args)
|
63
134
|
|
data/lib/calyx/modifiers.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
module Calyx
|
2
|
+
# Applies modifiers to the output of a rule in a template substitution.
|
2
3
|
class Modifiers
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# Transforms an output string by delegating to the given output function.
|
5
|
+
#
|
6
|
+
# If a registered modifier method is not found, then delegate to the given
|
7
|
+
# string function.
|
8
|
+
#
|
9
|
+
# If an invalid modifier function is given, returns the raw input string.
|
10
|
+
#
|
11
|
+
# @param name [Symbol]
|
12
|
+
# @param value [String]
|
13
|
+
# @return [String]
|
7
14
|
def transform(name, value)
|
8
15
|
if respond_to?(name)
|
9
16
|
send(name, value)
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module Calyx
|
2
|
+
# A type of production rule representing a list of possible rules, one of
|
3
|
+
# which will chosen each time the grammar runs.
|
2
4
|
module Production
|
3
5
|
class Choices
|
6
|
+
# Parse a list of productions and return a choice node which is the head
|
7
|
+
# of a syntax tree of child nodes.
|
8
|
+
#
|
9
|
+
# @param productions [Array]
|
10
|
+
# @param registry [Calyx::Registry]
|
4
11
|
def self.parse(productions, registry)
|
5
12
|
choices = productions.map do |choice|
|
6
13
|
if choice.is_a?(String)
|
@@ -18,10 +25,16 @@ module Calyx
|
|
18
25
|
self.new(choices)
|
19
26
|
end
|
20
27
|
|
28
|
+
# Initialize a new choice with a list of child nodes.
|
29
|
+
#
|
30
|
+
# @param collection [Array]
|
21
31
|
def initialize(collection)
|
22
32
|
@collection = collection
|
23
33
|
end
|
24
34
|
|
35
|
+
# Evaluate the choice by randomly picking one of its possible options.
|
36
|
+
#
|
37
|
+
# @return [Array]
|
25
38
|
def evaluate
|
26
39
|
[:choice, @collection.sample.evaluate]
|
27
40
|
end
|
@@ -1,11 +1,20 @@
|
|
1
1
|
module Calyx
|
2
2
|
module Production
|
3
|
+
# A type of production rule representing a string combining both template
|
4
|
+
# substitutions and raw content.
|
3
5
|
class Concat
|
4
6
|
EXPRESSION = /(\{[A-Za-z0-9_@\.]+\})/.freeze
|
5
7
|
START_TOKEN = '{'.freeze
|
6
8
|
END_TOKEN = '}'.freeze
|
7
9
|
DEREF_TOKEN = '.'.freeze
|
8
10
|
|
11
|
+
# Parses an interpolated string into fragments combining terminal strings
|
12
|
+
# and non-terminal rules.
|
13
|
+
#
|
14
|
+
# Returns a concat node which is the head of a tree of child nodes.
|
15
|
+
#
|
16
|
+
# @param production [String]
|
17
|
+
# @param registry [Calyx::Registry]
|
9
18
|
def self.parse(production, registry)
|
10
19
|
expansion = production.split(EXPRESSION).map do |atom|
|
11
20
|
if atom.is_a?(String)
|
@@ -30,10 +39,18 @@ module Calyx
|
|
30
39
|
self.new(expansion)
|
31
40
|
end
|
32
41
|
|
42
|
+
# Initialize the concat node with an expansion of terminal and
|
43
|
+
# non-terminal fragments.
|
44
|
+
#
|
45
|
+
# @param expansion [Array]
|
33
46
|
def initialize(expansion)
|
34
47
|
@expansion = expansion
|
35
48
|
end
|
36
49
|
|
50
|
+
# Evaluate all the child nodes of this node and concatenate them together
|
51
|
+
# into a single result.
|
52
|
+
#
|
53
|
+
# @return [Array]
|
37
54
|
def evaluate
|
38
55
|
concat = @expansion.reduce([]) do |exp, atom|
|
39
56
|
exp << atom.evaluate
|
@@ -1,12 +1,23 @@
|
|
1
1
|
module Calyx
|
2
2
|
module Production
|
3
|
+
# A type of production rule representing a single template substitution.
|
3
4
|
class Expression
|
5
|
+
# Constructs a node representing a single template substitution.
|
6
|
+
#
|
7
|
+
# @param production [#evaluate]
|
8
|
+
# @param methods [Array]
|
9
|
+
# @param registry [Calyx::Registry]
|
4
10
|
def initialize(production, methods, registry)
|
5
11
|
@production = production
|
6
12
|
@methods = methods.map { |m| m.to_sym }
|
7
13
|
@registry = registry
|
8
14
|
end
|
9
15
|
|
16
|
+
# Evaluate the expression by expanding the non-terminal to produce a
|
17
|
+
# terminal string, then passing it through the given modifier chain and
|
18
|
+
# returning the transformed result.
|
19
|
+
#
|
20
|
+
# @return [Array]
|
10
21
|
def evaluate
|
11
22
|
terminal = @production.evaluate.flatten.reject { |o| o.is_a?(Symbol) }.join(''.freeze)
|
12
23
|
expression = @methods.reduce(terminal) do |value, method|
|
@@ -1,13 +1,23 @@
|
|
1
1
|
module Calyx
|
2
2
|
module Production
|
3
|
+
# A type of production rule representing a memoized subsitution which
|
4
|
+
# returns the first value selected on all subsequent lookups.
|
3
5
|
class Memo
|
4
6
|
SIGIL = '@'.freeze
|
5
7
|
|
8
|
+
# Construct a memoized rule, given the symbol to lookup and the registry
|
9
|
+
# to look it up in.
|
10
|
+
#
|
11
|
+
# @param symbol [Symbol]
|
12
|
+
# @param registry [Calyx::Registry]
|
6
13
|
def initialize(symbol, registry)
|
7
14
|
@symbol = symbol.slice(1, symbol.length-1).to_sym
|
8
15
|
@registry = registry
|
9
16
|
end
|
10
17
|
|
18
|
+
# Evaluate the memo, using the registry to handle the expansion.
|
19
|
+
#
|
20
|
+
# @return [Array]
|
11
21
|
def evaluate
|
12
22
|
[@symbol, @registry.memoize_expansion(@symbol)]
|
13
23
|
end
|
@@ -1,11 +1,21 @@
|
|
1
1
|
module Calyx
|
2
2
|
module Production
|
3
|
+
# A type of production rule that represents a non-terminal expansion,
|
4
|
+
# linking one rule to another.
|
3
5
|
class NonTerminal
|
6
|
+
# Construct a non-terminal node, given the symbol to lookup and the
|
7
|
+
# registry to look it up in.
|
8
|
+
#
|
9
|
+
# @param symbol [Symbol]
|
10
|
+
# @param registry [Calyx::Registry]
|
4
11
|
def initialize(symbol, registry)
|
5
12
|
@symbol = symbol.to_sym
|
6
13
|
@registry = registry
|
7
14
|
end
|
8
15
|
|
16
|
+
# Evaluate the non-terminal, using the registry to handle the expansion.
|
17
|
+
#
|
18
|
+
# @return [Array]
|
9
19
|
def evaluate
|
10
20
|
[@symbol, @registry.expand(@symbol).evaluate]
|
11
21
|
end
|
@@ -1,10 +1,17 @@
|
|
1
1
|
module Calyx
|
2
2
|
module Production
|
3
|
+
# A type of production rule that terminates with a resulting string atom.
|
3
4
|
class Terminal
|
5
|
+
# Construct a terminal node with the given value.
|
6
|
+
#
|
7
|
+
# @param atom [#to_s]
|
4
8
|
def initialize(atom)
|
5
9
|
@atom = atom
|
6
10
|
end
|
7
11
|
|
12
|
+
# Evaluate the terminal by returning its identity directly.
|
13
|
+
#
|
14
|
+
# @return [Array]
|
8
15
|
def evaluate
|
9
16
|
[:atom, @atom]
|
10
17
|
end
|
@@ -1,12 +1,20 @@
|
|
1
1
|
module Calyx
|
2
2
|
module Production
|
3
|
+
# A type of production rule representing a map of possible rules with
|
4
|
+
# associated weights that define the expected probability of a rule
|
5
|
+
# being chosen.
|
3
6
|
class WeightedChoices
|
7
|
+
# Parse a given list or hash of productions into a syntax tree of weighted
|
8
|
+
# choices.
|
9
|
+
#
|
10
|
+
# @param productions [Array<Array>, Hash<#to_s, Float>]
|
11
|
+
# @param registry [Calyx::Registry]
|
4
12
|
def self.parse(productions, registry)
|
5
13
|
weights_sum = productions.reduce(0) do |memo, choice|
|
6
14
|
memo += choice.last
|
7
15
|
end
|
8
16
|
|
9
|
-
raise 'Weights must sum to 1' if weights_sum != 1.0
|
17
|
+
raise Errors::InvalidDefinition, 'Weights must sum to 1' if weights_sum != 1.0
|
10
18
|
|
11
19
|
choices = productions.map do |choice, weight|
|
12
20
|
if choice.is_a?(String)
|
@@ -19,10 +27,20 @@ module Calyx
|
|
19
27
|
self.new(choices)
|
20
28
|
end
|
21
29
|
|
30
|
+
# Initialize a new choice with a list of child nodes.
|
31
|
+
#
|
32
|
+
# @param collection [Array]
|
22
33
|
def initialize(collection)
|
23
34
|
@collection = collection
|
24
35
|
end
|
25
36
|
|
37
|
+
# Evaluate the choice by randomly picking one of its possible options,
|
38
|
+
# balanced according to the given weights.
|
39
|
+
#
|
40
|
+
# The method for selecting weighted probabilities is based on a snippet
|
41
|
+
# of code recommended in the Ruby standard library documentation.
|
42
|
+
#
|
43
|
+
# @return [Array]
|
26
44
|
def evaluate
|
27
45
|
choice = @collection.max_by do |_, weight|
|
28
46
|
rand ** (1.0 / weight)
|
data/lib/calyx/registry.rb
CHANGED
@@ -1,25 +1,42 @@
|
|
1
1
|
module Calyx
|
2
|
+
# Lookup table of all the available rules in the grammar.
|
2
3
|
class Registry
|
3
4
|
attr_reader :rules, :transforms, :modifiers
|
4
5
|
|
6
|
+
# Construct an empty registry.
|
5
7
|
def initialize
|
6
8
|
@rules = {}
|
7
9
|
@transforms = {}
|
8
10
|
@modifiers = Modifiers.new
|
9
11
|
end
|
10
12
|
|
13
|
+
# Hook for defining rules without explicitly calling the `#rule` method.
|
14
|
+
#
|
15
|
+
# @param name [Symbol]
|
16
|
+
# @param productions [Array]
|
11
17
|
def method_missing(name, *arguments)
|
12
18
|
rule(name, *arguments)
|
13
19
|
end
|
14
20
|
|
21
|
+
# Attaches a modifier module to this instance.
|
22
|
+
#
|
23
|
+
# @param module_name [Module]
|
15
24
|
def modifier(name)
|
16
|
-
modifiers.
|
25
|
+
modifiers.extend(name)
|
17
26
|
end
|
18
27
|
|
28
|
+
# Registers a paired mapping regex.
|
29
|
+
#
|
30
|
+
# @param name [Symbol]
|
31
|
+
# @param pairs [Hash<Regex,String>]
|
19
32
|
def mapping(name, pairs)
|
20
33
|
transforms[name.to_sym] = construct_mapping(pairs)
|
21
34
|
end
|
22
35
|
|
36
|
+
# Registers the given block as a string filter.
|
37
|
+
#
|
38
|
+
# @param name [Symbol]
|
39
|
+
# @block block with a single string argument returning a modified string.
|
23
40
|
def filter(name, callable=nil, &block)
|
24
41
|
if block_given?
|
25
42
|
transforms[name.to_sym] = block
|
@@ -28,14 +45,26 @@ module Calyx
|
|
28
45
|
end
|
29
46
|
end
|
30
47
|
|
48
|
+
# Registers a new grammar rule.
|
49
|
+
#
|
50
|
+
# @param name [Symbol]
|
51
|
+
# @param productions [Array]
|
31
52
|
def rule(name, *productions)
|
32
53
|
rules[name.to_sym] = construct_rule(productions)
|
33
54
|
end
|
34
55
|
|
56
|
+
# Expands the given rule symbol to its production.
|
57
|
+
#
|
58
|
+
# @param symbol [Symbol]
|
35
59
|
def expand(symbol)
|
36
60
|
rules[symbol] || context[symbol]
|
37
61
|
end
|
38
62
|
|
63
|
+
# Applies the given modifier function to the given value to transform it.
|
64
|
+
#
|
65
|
+
# @param name [Symbol]
|
66
|
+
# @param value [String]
|
67
|
+
# @return [String]
|
39
68
|
def transform(name, value)
|
40
69
|
if transforms.key?(name)
|
41
70
|
transforms[name].call(value)
|
@@ -44,20 +73,38 @@ module Calyx
|
|
44
73
|
end
|
45
74
|
end
|
46
75
|
|
76
|
+
# Expands a memoized rule symbol by evaluating it and storing the result
|
77
|
+
# for later.
|
78
|
+
#
|
79
|
+
# @param symbol [Symbol]
|
47
80
|
def memoize_expansion(symbol)
|
48
81
|
memos[symbol] ||= expand(symbol).evaluate
|
49
82
|
end
|
50
83
|
|
84
|
+
# Merges the given registry instance with the target registry.
|
85
|
+
#
|
86
|
+
# This is only needed at compile time, so that child classes can easily
|
87
|
+
# inherit the set of rules decared by their parent.
|
88
|
+
#
|
89
|
+
# @param registry [Calyx::Registry]
|
51
90
|
def combine(registry)
|
52
91
|
@rules = rules.merge(registry.rules)
|
53
92
|
end
|
54
93
|
|
94
|
+
# Evaluates the grammar defined in this registry, combining it with rules
|
95
|
+
# from the passed in context.
|
96
|
+
#
|
97
|
+
# Produces a syntax tree of nested list nodes.
|
98
|
+
#
|
99
|
+
# @param start_symbol [Symbol]
|
100
|
+
# @param rules_map [Hash]
|
101
|
+
# @return [Array]
|
55
102
|
def evaluate(start_symbol=:start, rules_map={})
|
56
103
|
reset_evaluation_context
|
57
104
|
|
58
105
|
rules_map.each do |key, value|
|
59
106
|
if rules.key?(key.to_sym)
|
60
|
-
raise
|
107
|
+
raise Errors::DuplicateRule.new(key)
|
61
108
|
end
|
62
109
|
|
63
110
|
context[key.to_sym] = if value.is_a?(Array)
|
@@ -72,7 +119,7 @@ module Calyx
|
|
72
119
|
if expansion.respond_to?(:evaluate)
|
73
120
|
[start_symbol, expansion.evaluate]
|
74
121
|
else
|
75
|
-
raise Errors::
|
122
|
+
raise Errors::MissingRule.new(start_symbol)
|
76
123
|
end
|
77
124
|
end
|
78
125
|
|
data/lib/calyx/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calyx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Rickerby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06
|
11
|
+
date: 2016-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,8 @@ files:
|
|
66
66
|
- LICENSE
|
67
67
|
- README.md
|
68
68
|
- calyx.gemspec
|
69
|
+
- examples/faker.rb
|
70
|
+
- examples/faker.yml
|
69
71
|
- examples/tiny_woodland.rb
|
70
72
|
- lib/calyx.rb
|
71
73
|
- lib/calyx/errors.rb
|