kotodama 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/wordgen +59 -0
- data/lib/kotodama.rb +23 -0
- data/lib/kotodama/array.rb +22 -0
- data/lib/kotodama/change.rb +103 -0
- data/lib/kotodama/change_list.rb +31 -0
- data/lib/kotodama/language.rb +62 -0
- data/lib/kotodama/parser.rb +151 -0
- data/lib/kotodama/rule.rb +31 -0
- data/lib/kotodama/string.rb +29 -0
- data/lib/kotodama/type.rb +33 -0
- data/lib/kotodama/word.rb +66 -0
- metadata +86 -0
data/bin/wordgen
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'kotodama'
|
4
|
+
|
5
|
+
flags = []
|
6
|
+
files = []
|
7
|
+
starting_rule = nil
|
8
|
+
starting_change = nil
|
9
|
+
number = 1
|
10
|
+
ARGV.each do |n|
|
11
|
+
if n[0] == '-'
|
12
|
+
case n[1]
|
13
|
+
when 'r'
|
14
|
+
starting_rule = n[2..-1]
|
15
|
+
when 'c'
|
16
|
+
starting_change = n[2..-1]
|
17
|
+
else
|
18
|
+
flags |= n[1..-1].split
|
19
|
+
end
|
20
|
+
elsif n.match /\A\d+\Z/
|
21
|
+
number = n.to_i
|
22
|
+
else
|
23
|
+
files << n
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if files.length == 1
|
28
|
+
File.open files[0] do |file|
|
29
|
+
result = Kotodama::Parser.new.parse file
|
30
|
+
if result.parsed?
|
31
|
+
lang = result.result
|
32
|
+
if flags.member? 'u'
|
33
|
+
trials = []
|
34
|
+
until trials.length == number
|
35
|
+
trials |= lang.generate
|
36
|
+
end
|
37
|
+
puts trials
|
38
|
+
else
|
39
|
+
number.times { puts lang.generate }
|
40
|
+
end
|
41
|
+
else
|
42
|
+
flags.member?('v') ? result.backtrace : STDERR.puts(result.error_message)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
elsif files.length == 2
|
46
|
+
File.open files[0] do |file|
|
47
|
+
result = Kotodama::Parser.new.parse file
|
48
|
+
if result.parsed?
|
49
|
+
lang = result.result
|
50
|
+
File.open files[1] do |file2|
|
51
|
+
puts lang.apply_to file2.to_a.collect {|n| n.chomp }
|
52
|
+
end
|
53
|
+
else
|
54
|
+
flags.member?('v') ? result.backtrace : STDERR.puts(result.error_message)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
STDERR.puts "wrong number of arguments (#{files.length} for 2)"
|
59
|
+
end
|
data/lib/kotodama.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'kaiseki'
|
3
|
+
|
4
|
+
module Kotodama
|
5
|
+
VERSION = '0.0.3'
|
6
|
+
end
|
7
|
+
|
8
|
+
dir_path = Pathname.new(__FILE__).realpath.dirname
|
9
|
+
|
10
|
+
[
|
11
|
+
'kotodama/word',
|
12
|
+
'kotodama/language',
|
13
|
+
'kotodama/type',
|
14
|
+
'kotodama/rule',
|
15
|
+
'kotodama/change',
|
16
|
+
'kotodama/change_list',
|
17
|
+
|
18
|
+
'kotodama/array',
|
19
|
+
'kotodama/string',
|
20
|
+
'kotodama/parser',
|
21
|
+
].each do |path|
|
22
|
+
require dir_path + path
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Array
|
2
|
+
def random weights = nil
|
3
|
+
if weights
|
4
|
+
if weights.length == self.length
|
5
|
+
max_weight = 0
|
6
|
+
weights.each {|n| max_weight += n }
|
7
|
+
target_weight = rand max_weight
|
8
|
+
index = 0
|
9
|
+
index_weight = weights[index]
|
10
|
+
while index_weight <= target_weight
|
11
|
+
index += 1
|
12
|
+
index_weight += weights[index]
|
13
|
+
end
|
14
|
+
self[index]
|
15
|
+
else
|
16
|
+
raise "Array length and weights length not equal (#{self.length} and #{weights.length})"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
self[rand(self.length)]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Kotodama
|
2
|
+
class Change
|
3
|
+
def initialize action, target, env
|
4
|
+
@action = action
|
5
|
+
@target = target
|
6
|
+
@env = env
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply_to word, options = {}
|
10
|
+
unless word.is_a? Word
|
11
|
+
word = word.to_word
|
12
|
+
end
|
13
|
+
i = 0
|
14
|
+
while i < word.length
|
15
|
+
if check_environment word, i, options
|
16
|
+
case @action
|
17
|
+
when :insert
|
18
|
+
@target.length.times do |i2|
|
19
|
+
word.insert i + i2, @target[i2]
|
20
|
+
end
|
21
|
+
i += @target.length - 1
|
22
|
+
when :delete
|
23
|
+
catch :fail do
|
24
|
+
@target.length.times do |i2|
|
25
|
+
if options[:lang].types.key? @target[i2]
|
26
|
+
throw :fail unless options[:lang].types[@target[i2]].has? word[i + i2]
|
27
|
+
else
|
28
|
+
throw :fail unless word[i + i2] == @target[i2]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
@target.each { word.delete_at i }
|
32
|
+
end
|
33
|
+
when :transform
|
34
|
+
catch :fail do
|
35
|
+
insertion_string = []
|
36
|
+
@target[0].length.times do |i2|
|
37
|
+
if options[:lang].types.key? @target[0][i2]
|
38
|
+
if options[:lang].types[@target[0][i2]].has?(word[i + i2])
|
39
|
+
insertion_string << options[:lang].types[@target[0][i2]].symbols.find_index(word[i + i2])
|
40
|
+
else
|
41
|
+
throw :fail
|
42
|
+
end
|
43
|
+
else
|
44
|
+
throw :fail unless word[i + i2] == @target[0][i2]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@target[0].each { word.delete_at i }
|
48
|
+
insertion_string.reverse!
|
49
|
+
@target[1].length.times do |i2|
|
50
|
+
if options[:lang].types.key? @target[1][i2]
|
51
|
+
raise "Wrong number of type transformations" unless insertion_string.last
|
52
|
+
word.insert i + i2, options[:lang].types[@target[1][i2]].symbols[insertion_string.pop]
|
53
|
+
else
|
54
|
+
word.insert i + i2, @target[1][i2]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
i += 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def check_environment word, index, options = {}
|
65
|
+
if @env
|
66
|
+
catch :fail do
|
67
|
+
@env[1].length.times do |i|
|
68
|
+
if @action == :insert
|
69
|
+
next_n = index + i
|
70
|
+
else
|
71
|
+
next_n = index + @target[0].length + i
|
72
|
+
end
|
73
|
+
if @env[1][i] == '#'
|
74
|
+
throw :fail unless index + 1 + i >= word.length
|
75
|
+
elsif options[:lang].types.key? @env[1][i]
|
76
|
+
throw :fail if next_n >= word.length
|
77
|
+
throw :fail unless options[:lang].types[@env[1][i]].has? word[next_n]
|
78
|
+
else
|
79
|
+
throw :fail if next_n >= word.length
|
80
|
+
throw :fail unless @env[1][i] == word[next_n]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
@env[0].length.times do |i|
|
84
|
+
last_n = index - @env[0].length + i
|
85
|
+
if @env[0][i] == '#'
|
86
|
+
throw :fail unless last_n < 0
|
87
|
+
elsif options[:lang].types.key? @env[0][i]
|
88
|
+
throw :fail if last_n < 0
|
89
|
+
throw :fail unless options[:lang].types[@env[0][i]].has? word[last_n]
|
90
|
+
else
|
91
|
+
throw :fail if last_n < 0
|
92
|
+
throw :fail unless @env[0][i] == word[last_n]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
return true
|
96
|
+
end
|
97
|
+
false
|
98
|
+
else
|
99
|
+
true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kotodama
|
2
|
+
class ChangeList
|
3
|
+
attr_reader :name, :list
|
4
|
+
|
5
|
+
def initialize name
|
6
|
+
@name = name
|
7
|
+
@list = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def push n
|
11
|
+
@list << n
|
12
|
+
end
|
13
|
+
|
14
|
+
alias :<< :push
|
15
|
+
|
16
|
+
def apply_to word, options = {}
|
17
|
+
@list.each do |n|
|
18
|
+
if n.is_a? Change
|
19
|
+
n.apply_to word, options
|
20
|
+
else
|
21
|
+
if options[:lang].changes.key? n
|
22
|
+
options[:lang].changes[n].apply_to word, options
|
23
|
+
else
|
24
|
+
raise "#{n} is not a sound change"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
word
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Kotodama
|
2
|
+
class Language
|
3
|
+
attr_reader :types, :rules, :changes, :options
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@types = {}
|
7
|
+
@rules = {}
|
8
|
+
@changes = {}
|
9
|
+
@options = {:symbol_weight => 1, :phrase_weight => 1}
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_type type
|
13
|
+
@types[type.name] = type
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_rule rule
|
17
|
+
@rules[rule.name] = rule
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_change change
|
21
|
+
@changes[change.name] = change
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_type symbol
|
25
|
+
@types.values.find {|n| n.has? symbol }
|
26
|
+
end
|
27
|
+
|
28
|
+
def generate starting_rule = nil, starting_change = nil
|
29
|
+
starting_rule ||= @options['rule']
|
30
|
+
starting_change ||= @options['change']
|
31
|
+
if @rules.key? starting_rule
|
32
|
+
word = @rules[starting_rule].generate @options.merge(:lang => self)
|
33
|
+
if starting_change
|
34
|
+
if @changes.key? starting_change
|
35
|
+
word.apply @changes[starting_change], @options.merge(:lang => self)
|
36
|
+
else
|
37
|
+
raise "#{starting_change || 'nil'} is not a sound change"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
word.to_s
|
41
|
+
else
|
42
|
+
raise "#{starting_rule || 'nil'} is not a rule"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def apply_to array, starting_change = nil
|
47
|
+
starting_change ||= @options['change']
|
48
|
+
if @changes.key? starting_change
|
49
|
+
array.collect do |n|
|
50
|
+
word = n.to_word
|
51
|
+
if word
|
52
|
+
word.apply @changes[starting_change], @options.merge(:lang => self)
|
53
|
+
else
|
54
|
+
"input `#{n}' cannot be correctly converted into a word"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
raise "#{starting_change || 'nil'} is not a sound change"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Kotodama
|
2
|
+
Parser = Kaiseki::Grammar.subclass do
|
3
|
+
starting :document
|
4
|
+
skipping /\s+/
|
5
|
+
simplify
|
6
|
+
|
7
|
+
rule :document do
|
8
|
+
parse :options_block.optional & :content_block.zero_or_more & :EOF
|
9
|
+
node :params => [:options, :content]
|
10
|
+
action do
|
11
|
+
lang = Language.new
|
12
|
+
lang.options.merge! @options
|
13
|
+
@content.each do |n|
|
14
|
+
if n.is_a? Type
|
15
|
+
lang.add_type n
|
16
|
+
elsif n.is_a? Rule
|
17
|
+
lang.add_rule n
|
18
|
+
elsif n.is_a? ChangeList
|
19
|
+
lang.add_change n
|
20
|
+
else
|
21
|
+
raise "#{n.class} is not a valid Language class"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
lang
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rule :options_block do
|
29
|
+
parse 'options'.skip & '{'.skip & :option.zero_or_more & '}'.skip
|
30
|
+
action do
|
31
|
+
options_hash = {}
|
32
|
+
@results.each {|n| options_hash.merge! n }
|
33
|
+
options_hash
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
rule :option do
|
38
|
+
parse :ID & '=>'.skip & (:ID | :INT) & ';'.skip
|
39
|
+
node :params => [:key, :value]
|
40
|
+
action { {@key => @value} }
|
41
|
+
end
|
42
|
+
|
43
|
+
rule :content_block do
|
44
|
+
parse :type_block | :rule_block | :change_block
|
45
|
+
end
|
46
|
+
|
47
|
+
rule :type_block do
|
48
|
+
parse 'type'.skip & :ID & '{'.skip & :symbol.zero_or_more & '}'.skip
|
49
|
+
node :params => [:name, :symbols]
|
50
|
+
action do
|
51
|
+
type = Type.new @name
|
52
|
+
@symbols.each do |symbol|
|
53
|
+
if symbol[0].respond_to? :each
|
54
|
+
symbol[0].each {|n| type.add_symbol n, symbol[1] }
|
55
|
+
else
|
56
|
+
type.add_symbol symbol[0], symbol[1]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
type
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
rule :symbol do
|
64
|
+
parse (:ID | :LIT) >> (','.skip & (:ID | :LIT)).zero_or_more & :weight.optional & ';'.skip
|
65
|
+
end
|
66
|
+
|
67
|
+
rule :rule_block do
|
68
|
+
parse 'rule'.skip & :ID & '{'.skip & :rule.zero_or_more & '}'.skip
|
69
|
+
node :params => [:name, :phrases]
|
70
|
+
action do
|
71
|
+
rule = Rule.new @name
|
72
|
+
@phrases.each {|phrase| rule.add_phrase phrase[0], phrase[1] }
|
73
|
+
rule
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
rule :rule do
|
78
|
+
parse (:ID | :LIT).one_or_more & :weight.optional & ';'.skip
|
79
|
+
end
|
80
|
+
|
81
|
+
rule :change_block do
|
82
|
+
parse 'change'.skip & :ID & '{'.skip & :change.zero_or_more & '}'.skip
|
83
|
+
node :params => [:name, :changes]
|
84
|
+
action do
|
85
|
+
change_list = ChangeList.new @name
|
86
|
+
@changes.each {|change| change_list.push change }
|
87
|
+
change_list
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
rule :change do
|
92
|
+
parse :insertion_change | :deletion_change | :transformation_change | :change_name
|
93
|
+
end
|
94
|
+
|
95
|
+
rule :insertion_change do
|
96
|
+
parse 'insert'.skip & (:ID | :LIT).one_or_more & :change_env.optional & ';'.skip
|
97
|
+
override :simplify => false
|
98
|
+
node :params => [:target, :env]
|
99
|
+
action do
|
100
|
+
Change.new :insert, @target, @env[0]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
rule :deletion_change do
|
105
|
+
parse 'delete'.skip & (:ID | :LIT).one_or_more & :change_env.optional & ';'.skip
|
106
|
+
override :simplify => false
|
107
|
+
node :params => [:target, :env]
|
108
|
+
action do
|
109
|
+
Change.new :delete, @target, @env[0]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
rule :transformation_change do
|
114
|
+
parse (:ID | :LIT).one_or_more & '>'.skip & (:ID | :LIT).one_or_more & :change_env.optional & ';'.skip
|
115
|
+
override :simplify => false
|
116
|
+
node :params => [:target1, :target2, :env]
|
117
|
+
action do
|
118
|
+
Change.new :transform, [@target1, @target2], @env[0]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
rule :change_name do
|
123
|
+
parse :ID & ';'.skip
|
124
|
+
end
|
125
|
+
|
126
|
+
rule :change_env do
|
127
|
+
parse '/'.skip & ('#'.optional >> :ID.zero_or_more) & '_'.skip & (:ID.zero_or_more >> '#'.optional)
|
128
|
+
action { @results.to_a }
|
129
|
+
end
|
130
|
+
|
131
|
+
rule :weight do
|
132
|
+
parse ':'.skip & :INT
|
133
|
+
override :simplify => true
|
134
|
+
end
|
135
|
+
|
136
|
+
rule :ID do
|
137
|
+
parse /_*[a-zA-Z][a-zA-Z0-9_]*/
|
138
|
+
action { @results.to_s }
|
139
|
+
end
|
140
|
+
|
141
|
+
rule :INT do
|
142
|
+
parse /\d+/
|
143
|
+
action { @results.to_i }
|
144
|
+
end
|
145
|
+
|
146
|
+
rule :LIT do
|
147
|
+
parse /\'([^']*)\'/ | /\"([^"]*)\"/
|
148
|
+
action { @results.info[:captures][0] }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kotodama
|
2
|
+
class Rule
|
3
|
+
attr_reader :name, :phrases, :weights
|
4
|
+
|
5
|
+
def initialize name
|
6
|
+
@name = name
|
7
|
+
@phrases = []
|
8
|
+
@weights = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_phrase rule, weight = 1
|
12
|
+
@phrases << rule
|
13
|
+
@weights << weight
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate options = {}
|
17
|
+
word = Word.new
|
18
|
+
phrase = @phrases.random @weights.collect {|n| n || options[:phrase_weight] || 1 }
|
19
|
+
phrase.each do |n|
|
20
|
+
if options[:lang].rules.key? n
|
21
|
+
word << options[:lang].rules[n].generate(options)
|
22
|
+
elsif options[:lang].types.key? n
|
23
|
+
word << options[:lang].types[n].generate(options)
|
24
|
+
else
|
25
|
+
word << n
|
26
|
+
end
|
27
|
+
end
|
28
|
+
word
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class String
|
2
|
+
def to_word language
|
3
|
+
max_symbol_length = 0
|
4
|
+
language.types.each_pair do |key, type|
|
5
|
+
type.each do |symbol|
|
6
|
+
max_symbol_length = symbol.length if symbol.length > max_symbol_length
|
7
|
+
end
|
8
|
+
end
|
9
|
+
word = Kotodama::Word.new
|
10
|
+
index = 0
|
11
|
+
catch :fail do
|
12
|
+
while index < self.length
|
13
|
+
catch :succeed do
|
14
|
+
max_symbol_length.downto 1 do |length|
|
15
|
+
type = language.find_type self[index, length]
|
16
|
+
if type
|
17
|
+
word << self[index, length]
|
18
|
+
index += length
|
19
|
+
throw :succeed
|
20
|
+
end
|
21
|
+
end
|
22
|
+
throw :fail
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return word
|
26
|
+
end
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Kotodama
|
2
|
+
class Type
|
3
|
+
include Enumerable
|
4
|
+
attr_reader :name, :symbols, :weights
|
5
|
+
|
6
|
+
def initialize name
|
7
|
+
@name = name
|
8
|
+
@symbols = []
|
9
|
+
@weights = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_symbol symbol, weight = 1
|
13
|
+
@symbols << symbol
|
14
|
+
@weights << weight
|
15
|
+
end
|
16
|
+
|
17
|
+
def [] n
|
18
|
+
@symbols[n]
|
19
|
+
end
|
20
|
+
|
21
|
+
def each &block
|
22
|
+
@symbols.each &block
|
23
|
+
end
|
24
|
+
|
25
|
+
def has? symbol
|
26
|
+
@symbols.member? symbol
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate options = {}
|
30
|
+
@symbols.random(@weights.collect {|n| n || options[:symbol_weight] || 1 })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Kotodama
|
2
|
+
class Word
|
3
|
+
include Enumerable
|
4
|
+
attr_reader :letters
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@letters = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def [] n
|
11
|
+
@letters[n]
|
12
|
+
end
|
13
|
+
|
14
|
+
def []= n, value
|
15
|
+
@letters[n] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def empty?
|
19
|
+
@letters.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def length
|
23
|
+
@letters.length
|
24
|
+
end
|
25
|
+
|
26
|
+
def push letter
|
27
|
+
if letter.is_a? Word
|
28
|
+
letter.each {|n| @letters.push n }
|
29
|
+
else
|
30
|
+
@letters.push letter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :<< :push
|
35
|
+
|
36
|
+
def insert index, letter
|
37
|
+
if letter.is_a? Word
|
38
|
+
letter.length.times do |i|
|
39
|
+
@letters.insert index + i, letter[i]
|
40
|
+
end
|
41
|
+
else
|
42
|
+
@letters.insert index, letter
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_at index
|
47
|
+
@letters.delete_at index
|
48
|
+
end
|
49
|
+
|
50
|
+
def each &block
|
51
|
+
@letters.each &block
|
52
|
+
end
|
53
|
+
|
54
|
+
def apply change, options = {}
|
55
|
+
change.apply_to self, options
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
@letters.join
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_word *args
|
63
|
+
self
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kotodama
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- William Hamilton-Levi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-23 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: kaiseki
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: A word generator written in Ruby.
|
34
|
+
email: whamilt1@swarthmore.edu
|
35
|
+
executables:
|
36
|
+
- wordgen
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files: []
|
40
|
+
|
41
|
+
files:
|
42
|
+
- lib/kotodama.rb
|
43
|
+
- lib/kotodama/type.rb
|
44
|
+
- lib/kotodama/word.rb
|
45
|
+
- lib/kotodama/change.rb
|
46
|
+
- lib/kotodama/array.rb
|
47
|
+
- lib/kotodama/rule.rb
|
48
|
+
- lib/kotodama/change_list.rb
|
49
|
+
- lib/kotodama/string.rb
|
50
|
+
- lib/kotodama/language.rb
|
51
|
+
- lib/kotodama/parser.rb
|
52
|
+
- bin/wordgen
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: http://github.com/phi2dao/Kotodama
|
55
|
+
licenses: []
|
56
|
+
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.7
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: A word generator written in Ruby.
|
85
|
+
test_files: []
|
86
|
+
|