tra38-calyx 0.6.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 85ba5ec4d74873b85ad9e7aafd4694191717b00b
4
+ data.tar.gz: 93e6e5cc487f09443953e46d334e746aff12d919
5
+ SHA512:
6
+ metadata.gz: 88d7fd63cdf3e7cd491cd001093d5762e5a0b8dff5716d493bafb0afde2d2ffef82014f5fb68a5bdfdcd94b19fd24b8ac215f1e18a4aa77f4f41ffca9b7e33f8
7
+ data.tar.gz: 0c407e12b96da714500fb2827bf62c2f28ab9e6ae5fd97fea4535f672672e6f685cfede0d5f2e36ea64e104c07f9bf0aa74650b7a7d7ffa91a6c5a7a88335976
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /*.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.2
5
+ - rbx-2
6
+ - jruby-9
7
+ - jruby-head
8
+ before_install: gem install bundler -v 1.10.6
9
+ script: bundle exec rspec
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Mark Rickerby
4
+ Copyright (c) 2016 Tariq Ali
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,282 @@
1
+ # Calyx
2
+
3
+ Calyx provides a simple API for generating text with declarative recursive grammars.
4
+
5
+ ## Install
6
+
7
+ ### Command Line
8
+
9
+ ```
10
+ gem install calyx
11
+ ```
12
+
13
+ ## Gemfile
14
+
15
+ ```
16
+ gem 'calyx'
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Calyx support two types of classes.
22
+
23
+ Classes that inherit from `Calyx::Grammar` are used to construct a set of rules that can generate a text. All grammars require a `start` rule, which specifies the starting point for generating the text structure.
24
+
25
+ Classes that inherit from `Calyx::DataTemplate` are used to construct a set of "meta-rules" that will invoke Grammar rules for you. All templates require a `write_narrative` method which specifies what "meta-rules" are being called.
26
+
27
+ ```ruby
28
+ require 'calyx'
29
+
30
+ class HelloWorld < Calyx::Grammar
31
+ start "Hello World."
32
+ end
33
+
34
+ class Greeting < Calyx::DataTemplate
35
+ def write_narrative
36
+ write HelloWorld
37
+ end
38
+ end
39
+ ```
40
+
41
+ There are two ways to generate text. You can generate text using Calyx::Grammar by initializing the object and calling the `generate` method.
42
+
43
+ ```ruby
44
+ hello = HelloWorld.new
45
+ hello.generate
46
+ # > "Hello World."
47
+ ```
48
+
49
+ Or, you can generate text by initializing the Calyx::DataTemplate class and calling the `result` method.
50
+ ```ruby
51
+ greeting = Greeting.new
52
+ greeting.result
53
+ # > "Hello World."
54
+ ```
55
+
56
+ ### Calyx::Grammar
57
+ Obviously, "Hello World" isn’t very interesting by itself. Possible variations can be added to the text using the `rule` constructor to provide a named set of text strings and the rule delimiter syntax (`{}`) within the text strings to substitute the generated content of the rule.
58
+
59
+ ```ruby
60
+ class HelloWorld < Calyx::Grammar
61
+ start '{greeting} world.'
62
+ rule :greeting, 'Hello', 'Hi', 'Hey', 'Yo'
63
+ end
64
+
65
+ hello = HelloWorld.new
66
+
67
+ hello.generate
68
+ # > "Hi world."
69
+
70
+ hello.generate
71
+ # > "Hello world."
72
+
73
+ hello.generate
74
+ # > "Yo world."
75
+ ```
76
+
77
+ Rules are recursive. They can be arbitrarily nested and connected to generate larger and more complex texts.
78
+
79
+ ```ruby
80
+ class HelloWorld < Calyx::Grammar
81
+ start '{greeting} {world_phrase}.'
82
+ rule :greeting, 'Hello', 'Hi', 'Hey', 'Yo'
83
+ rule :world_phrase, '{happy_adj} world', '{sad_adj} world', 'world'
84
+ rule :happy_adj, 'wonderful', 'amazing', 'bright', 'beautiful'
85
+ rule :sad_adj, 'cruel', 'miserable'
86
+ end
87
+ ```
88
+
89
+ Nesting and hierarchy can be manipulated to balance consistency with variation. The exact same word atoms can be combined in different ways to produce strikingly different resulting texts.
90
+
91
+ ```ruby
92
+ module HelloWorld
93
+ Sentiment < Calyx::Grammar
94
+ start '{happy_phrase}', '{sad_phrase}'
95
+ rule :happy_phrase, '{happy_greeting} {happy_adj} world.'
96
+ rule :happy_greeting, 'Hello', 'Hi', 'Hey', 'Yo'
97
+ rule :happy_adj, 'wonderful', 'amazing', 'bright', 'beautiful'
98
+ rule :sad_phrase, '{sad_greeting} {sad_adj} world.'
99
+ rule :sad_greeting, 'Goodbye', 'So long', 'Farewell'
100
+ rule :sad_adj, 'cruel', 'miserable'
101
+ end
102
+
103
+ Mixed < Calyx::Grammar
104
+ start '{greeting} {adj} world.'
105
+ rule :greeting, 'Hello', 'Hi', 'Hey', 'Yo', 'Goodbye', 'So long', 'Farewell'
106
+ rule :adj, 'wonderful', 'amazing', 'bright', 'beautiful', 'cruel', 'miserable'
107
+ end
108
+ end
109
+ ```
110
+
111
+ By default, the outcomes of generated rules are selected with Ruby’s built-in random number generator (as seen in methods like `Kernel.rand` and `Array.sample`). If you want to supply a weighted probability list, you can pass in arrays to the rule constructor, with the first argument being the template text string and the second argument being a float representing the probability between `0` and `1` of this choice being selected.
112
+
113
+ For example, you can model the triangular distribution produced by rolling 2d6:
114
+
115
+ ```ruby
116
+ class Roll2D6 < Calyx::Grammar
117
+ start(
118
+ ['2', 0.0278],
119
+ ['3', 0.556],
120
+ ['4', 0.833],
121
+ ['5', 0.1111],
122
+ ['6', 0.1389],
123
+ ['7', 0.1667],
124
+ ['8', 0.1389],
125
+ ['9', 0.1111],
126
+ ['10', 0.833],
127
+ ['11', 0.556],
128
+ ['12', 0.278]
129
+ )
130
+ end
131
+ ```
132
+
133
+ Or reproduce Gary Gygax’s famous generation table from the original Dungeon Master’s Guide (page 171):
134
+
135
+ ```ruby
136
+ class ChamberOrRoomContents < Calyx::Grammar
137
+ start(
138
+ [:empty, 0.6],
139
+ [:monster, 0.1],
140
+ [:monster_treasure, 0.15],
141
+ [:special, 0.05],
142
+ [:trick_trap, 0.05],
143
+ [:treasure, 0.05]
144
+ )
145
+
146
+ rule :empty, 'Empty'
147
+ rule :monster, 'Monster Only'
148
+ rule :monster_treasure, 'Monster and Treasure'
149
+ rule :special, 'Special'
150
+ rule :trick_trap, 'Trick/Trap.'
151
+ rule :treasure, 'Treasure'
152
+ end
153
+ ```
154
+
155
+ Dot-notation is supported in template expressions, allowing you to call any available method on the `String` object returned from a rule. Formatting methods can be chained arbitrarily and will execute in the same way as they would in native Ruby code.
156
+
157
+ ```ruby
158
+ class Greeting < Calyx::Grammar
159
+ start '{hello.capitalize} there.', 'Why, {hello} there.'
160
+ rule :hello, 'hello'
161
+ end
162
+
163
+ # => "Hello there."
164
+ # => "Why, hello there."
165
+ ```
166
+
167
+ In order to use more intricate natural language processing capabilities, you can embed additional methods onto the `String` class yourself, as well as use methods from existing Gems that monkeypatch `String`.
168
+
169
+ ```ruby
170
+ require 'indefinite_article'
171
+
172
+ module FullStop
173
+ def full_stop
174
+ self << '.'
175
+ end
176
+ end
177
+
178
+ class String
179
+ include FullStop
180
+ end
181
+
182
+ class NounsWithArticles < Calyx::Grammar
183
+ start '{fruit.with_indefinite_article.capitalize.full_stop}'
184
+ rule :fruit, 'apple', 'orange', 'banana', 'pear'
185
+ end
186
+
187
+ # => "An apple."
188
+ # => "An orange."
189
+ # => "A banana."
190
+ # => "A pear."
191
+ ```
192
+
193
+ ### Calyx::DataTemplate
194
+ Calyx::DataTemplate is useful for allowing a computer to write stories based on data stored within a Hash. The data can be plugged instantly into generated content, so long as you use erb syntax (to distingush from the rule delimiter syntax).
195
+
196
+ ```ruby
197
+ class StockReport < Calyx::Grammar
198
+ start "The price of one share of <%= name %> on <%= date %> is <%= price %> Yen."
199
+ end
200
+
201
+ class StockWriter < Calyx::DataTemplate
202
+ def write_narrative
203
+ write StockReport
204
+ end
205
+ end
206
+
207
+ cyberdyne = { :name => "Cyberdyne", :price => 1897.0, :date => Date.new(2015,1,14) }
208
+
209
+ stock_writer = StockWriter.new(cyberdyne)
210
+ stock_writer.result
211
+ # => "The price of one share of Cyberdyne on 2015-01-14 is 1897.0 Yen."
212
+ ```
213
+
214
+ `conditional_write` allows Calyx::DataTemplate to choose what grammar rule to invoke. If the condition is true, use the first grammar; otherwise, use the second grammar.
215
+ ```ruby
216
+ class GoodStock < Calyx::Grammar
217
+ start "You should buy stock in <%= name %> because this company has a low EPS."
218
+ end
219
+
220
+ class BadStock < Calyx:Grammar
221
+ start "You should sell stock in <%= name %> because this company has a high EPS."
222
+ end
223
+
224
+ class StockWriter < Calyx::DataTemplate
225
+ def write_narrative
226
+ conditional_write eps <= 20, GoodStock, BadStock
227
+ end
228
+ end
229
+
230
+ mitsui = { :name => "Mitsui", :eps => 15.8}
231
+ mitsui_writer = StockWriter.new(mitsui)
232
+ mitsui_writer.result
233
+ # => "You should buy stock in Mitsui because this company has a low EPS."
234
+
235
+ tokoyo_electric = { :name => "Tokyo Electric Power", :eps => 275.2 }
236
+ tokoyo_electric_writer = StockWriter.new(tokoyo_electric)
237
+ tokoyo_electric_writer.result
238
+ # => "You should sell stock in Tokoyo Electric Power because this company has a high EPS."
239
+ ```
240
+
241
+ You may also only provide only one grammar for `conditional_write`. If the condition is false, then nothing will be written.
242
+ ```ruby
243
+ class StockWriter < Calyx::DataTemplate
244
+ def write_narrative
245
+ conditional_write eps <= 20, GoodStock
246
+ end
247
+ end
248
+
249
+ tokoyo_electric = { :name => "Tokyo Electric Power", :eps => 275.2 }
250
+ tokoyo_electric_writer = StockWriter.new(tokoyo_electric)
251
+ tokoyo_electric_writer.result
252
+ # => ""
253
+ ```
254
+
255
+ By simply specifying a few "meta-rules" with conditionals and Grammars, you can generate unique, readable narratives based on your data.
256
+ ```ruby
257
+ class StockWriter < Calyx::DataTemplate
258
+ def write_narrative
259
+ write StockReport
260
+ conditional_write eps <= 20, GoodStock, BadStock
261
+ conditional_write eps <= 10, WonderfulStock
262
+ conditional_write eps >= 50, AbsolutelyHorribleStock
263
+ write ThanksForReading
264
+ end
265
+ end
266
+ ```
267
+
268
+ ###
269
+
270
+ ## License
271
+
272
+ Calyx is open source and provided under the terms of the MIT license. Copyright (c) 2015 Mark Rickerby, (c) 2016 Tariq Ali
273
+
274
+ See the `LICENSE` file [included with the project distribution](https://github.com/tra38/calyx/blob/master/LICENSE) for more information.
275
+
276
+ ## History
277
+ In November 2015, Mark Rickerby created Calyx and used that gem to create [choose-your-own adventure gamebooks](https://github.com/dariusk/NaNoGenMo-2015/issues/189). He later on wrote a [blog post](http://maetl.net/notes/storyboard/gamebook-of-dungeon-tropes) explaining his thought process.
278
+
279
+ In January 2016, Tariq Ali forked Calyx and started adding in new features to turn Calyx into a useful tool for generating data-driven narratives (robojournalism).
280
+
281
+ ## Disclaimer
282
+ In the real world, you would probably not want to buy or sell Japanese stock based solely on EPS. [The MIT Encyclopedia of the Japanese Economy](https://books.google.com/books?id=0RS0CGUaef8C&pg=PA423&lpg=PA423&dq=high+earnings+per+share+in+japan&source=bl&ots=sR8KV0fBTk&sig=qHspeX72SmpsU25wz9AZnhaAxyU&hl=en&sa=X&ved=0ahUKEwjcnqqctrLKAhWKRiYKHdKACaoQ6AEIHDAA#v=onepage&q=high%20earnings%20per%20share%20in%20japan&f=false) can provide some reasons why.
data/calyx.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'calyx/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'tra38-calyx'
8
+ spec.version = Calyx::VERSION
9
+ spec.authors = ['Mark Rickerby','Tariq Ali']
10
+ spec.email = ['me@maetl.net','tra38@nau.edu']
11
+
12
+ spec.summary = %q{Generate text with declarative recursive grammars}
13
+ spec.description = %q{Calyx provides a simple API for generating text with declarative recursive grammars.}
14
+ spec.homepage = 'https://github.com/tra38/calyx'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.10'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'rspec'
24
+ end
data/lib/calyx.rb ADDED
@@ -0,0 +1,217 @@
1
+ require 'erb'
2
+
3
+ module Calyx
4
+ #The Grammar class and the Production module was written by Mark Rickerby in 2015, and licensed under the MIT license.
5
+ class Grammar
6
+ class << self
7
+ attr_accessor :registry
8
+
9
+ def start(*productions, &production)
10
+ registry[:start] = construct_rule(productions)
11
+ end
12
+
13
+ def rule(name, *productions, &production)
14
+ registry[name.to_sym] = construct_rule(productions)
15
+ end
16
+
17
+ def inherit_registry(rules)
18
+ @registry ||= {}
19
+ @registry.merge!(rules || {})
20
+ end
21
+
22
+ def inherited(subclass)
23
+ subclass.inherit_registry(@registry)
24
+ end
25
+
26
+ private
27
+
28
+ def construct_rule(productions)
29
+ if productions.first.is_a?(Enumerable)
30
+ Production::WeightedChoices.parse(productions, registry)
31
+ else
32
+ Production::Choices.parse(productions, registry)
33
+ end
34
+ end
35
+ end
36
+
37
+ module Production
38
+ class NonTerminal
39
+ def initialize(expansion, registry)
40
+ @expansion = expansion.to_sym
41
+ @registry = registry
42
+ end
43
+
44
+ def evaluate
45
+ @registry[@expansion].evaluate
46
+ end
47
+ end
48
+
49
+ class Terminal
50
+ def initialize(atom)
51
+ @atom = atom
52
+ end
53
+
54
+ def evaluate
55
+ @atom
56
+ end
57
+ end
58
+
59
+ class Expression
60
+ def initialize(production, methods)
61
+ @production = production
62
+ @methods = methods.map { |m| m.to_sym }
63
+ end
64
+
65
+ def evaluate
66
+ @methods.reduce(@production.evaluate) do |value,method|
67
+ value.send(method)
68
+ end
69
+ end
70
+ end
71
+
72
+ class Concat
73
+ EXPRESSION = /(\{[A-Za-z0-9_\.]+\})/.freeze
74
+ START_TOKEN = '{'.freeze
75
+ END_TOKEN = '}'.freeze
76
+ DEREF_TOKEN = '.'.freeze
77
+
78
+ def self.parse(production, registry)
79
+ expansion = production.split(EXPRESSION).map do |atom|
80
+ if atom.is_a?(String)
81
+ if atom.chars.first == START_TOKEN && atom.chars.last == END_TOKEN
82
+ head, *tail = atom.slice(1, atom.length-2).split(DEREF_TOKEN)
83
+ rule = NonTerminal.new(head, registry)
84
+ unless tail.empty?
85
+ Expression.new(rule, tail)
86
+ else
87
+ rule
88
+ end
89
+ else
90
+ Terminal.new(atom)
91
+ end
92
+ elsif atom.is_a?(Symbol)
93
+ NonTerminal.new(atom, registry)
94
+ end
95
+ end
96
+
97
+ self.new(expansion)
98
+ end
99
+
100
+ def initialize(expansion)
101
+ @expansion = expansion
102
+ end
103
+
104
+ def evaluate
105
+ @expansion.reduce('') do |exp, atom|
106
+ exp << atom.evaluate
107
+ end
108
+ end
109
+ end
110
+
111
+ class WeightedChoices
112
+ def self.parse(productions, registry)
113
+ weights_sum = productions.reduce(0) do |memo, choice|
114
+ memo += choice.last
115
+ end
116
+
117
+ raise 'Weights must sum to 1' if weights_sum != 1.0
118
+
119
+ choices = productions.map do |choice, weight|
120
+ if choice.is_a?(String)
121
+ [Concat.parse(choice, registry), weight]
122
+ elsif choice.is_a?(Symbol)
123
+ [NonTerminal.new(choice, registry), weight]
124
+ end
125
+ end
126
+
127
+ self.new(choices)
128
+ end
129
+
130
+ def initialize(collection)
131
+ @collection = collection
132
+ end
133
+
134
+ def evaluate
135
+ choice = @collection.max_by do |_, weight|
136
+ rand ** (1.0 / weight)
137
+ end.first
138
+
139
+ choice.evaluate
140
+ end
141
+ end
142
+
143
+ class Choices
144
+ def self.parse(productions, registry)
145
+ choices = productions.map do |choice|
146
+ if choice.is_a?(String)
147
+ Concat.parse(choice, registry)
148
+ elsif choice.is_a?(Symbol)
149
+ NonTerminal.new(choice, registry)
150
+ end
151
+ end
152
+ self.new(choices)
153
+ end
154
+
155
+ def initialize(collection)
156
+ @collection = collection
157
+ end
158
+
159
+ def evaluate
160
+ @collection.sample.evaluate
161
+ end
162
+ end
163
+ end
164
+
165
+ def initialize(seed=nil)
166
+ @seed = seed
167
+ @seed = Time.new.to_i unless @seed
168
+ srand(@seed)
169
+ end
170
+
171
+ def registry
172
+ self.class.registry
173
+ end
174
+
175
+ def generate
176
+ registry[:start].evaluate
177
+ end
178
+ end
179
+
180
+ #The DataTemplate class was written by Tariq Ali in 2016, and licensed under the MIT License.
181
+ class DataTemplate
182
+ attr_reader :narrative
183
+
184
+ def initialize(data_hash = {})
185
+ data_hash.each do |key, value|
186
+ self.define_singleton_method(:"#{key}") do
187
+ value
188
+ end
189
+ end
190
+ @narrative = []
191
+ write_narrative
192
+ end
193
+
194
+ def write_narrative
195
+ #user writes in what should happened next
196
+ raise "There is no 'write_narrative' method present in your class."
197
+ end
198
+
199
+ def write(klass)
200
+ @narrative << klass.new.generate
201
+ end
202
+
203
+ def conditional_write(condition, klass_a, klass_b = nil)
204
+ if condition
205
+ @narrative << klass_a.new.generate
206
+ elsif klass_b
207
+ @narrative << klass_b.new.generate
208
+ else
209
+ end
210
+ end
211
+
212
+ def result
213
+ ERB.new(@narrative.join(" ")).result(binding)
214
+ end
215
+
216
+ end
217
+ end
@@ -0,0 +1,3 @@
1
+ module Calyx
2
+ VERSION = '0.6.2'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tra38-calyx
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.2
5
+ platform: ruby
6
+ authors:
7
+ - Mark Rickerby
8
+ - Tariq Ali
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-01-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.10'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.10'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: Calyx provides a simple API for generating text with declarative recursive
57
+ grammars.
58
+ email:
59
+ - me@maetl.net
60
+ - tra38@nau.edu
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".travis.yml"
68
+ - Gemfile
69
+ - LICENSE
70
+ - README.md
71
+ - calyx.gemspec
72
+ - lib/calyx.rb
73
+ - lib/calyx/version.rb
74
+ homepage: https://github.com/tra38/calyx
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.4.8
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Generate text with declarative recursive grammars
98
+ test_files: []