diachronr 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +6 -0
- data/README.md +30 -0
- data/Rakefile +13 -0
- data/diachronr.gemspec +26 -0
- data/lib/diachronr.rb +12 -0
- data/lib/diachronr/category.rb +12 -0
- data/lib/diachronr/rewrite.rb +20 -0
- data/lib/diachronr/rule.rb +102 -0
- data/lib/diachronr/ruleset.rb +40 -0
- data/lib/diachronr/version.rb +5 -0
- data/test/diachronr_test.rb +38 -0
- data/test/fixtures/seonic_to_varag.yml +119 -0
- data/test/test_helper.rb +2 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9b2e2d058e7f5f172916afd00f908040629c680a
|
4
|
+
data.tar.gz: d2f09d22747c1a296eb934cb46cd71a2b532d000
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3359a50b580a06e15ff588e7dffc85e7cf8ab7e2ef4714111e26881722cd6a3950f133eeb00dd648e30b4e5b9b650e3591117c0a16e6c4b17c6e56bf375bfdd5
|
7
|
+
data.tar.gz: 3db05f89d3c90c60014449877464124d5dd1696320ea57106ea89a81a142f171ba60b211e4333ed23fe000d2513674f07feb478f52b5808e75a2fc584ebbe033
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Intro
|
2
|
+
|
3
|
+
This is a basic gem for applying diachronic sound changes to words based on supplied rules. It is largely inspired by Mark Rosenfelder's Sound Change Applier(http://www.zompist.com/sca2.html, y'all should buy his books, too).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'diachronr'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install diachronr
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage documentation. For now, check out the tests
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Ensure your tests pass, coverage is at 100%, and rubocop reports clean
|
28
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
29
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
30
|
+
6. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
task :console do
|
4
|
+
require 'irb'
|
5
|
+
require 'irb/completion'
|
6
|
+
require 'diachronr' # You know what to do.
|
7
|
+
ARGV.clear
|
8
|
+
IRB.start
|
9
|
+
end
|
10
|
+
|
11
|
+
task :test do
|
12
|
+
Dir.glob('./test/*_test.rb').each { |file| require file }
|
13
|
+
end
|
data/diachronr.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'diachronr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'diachronr'
|
8
|
+
gem.version = Diachronr::VERSION
|
9
|
+
gem.authors = ['Miker Irick']
|
10
|
+
gem.email = ['michaelirick@gmail.com']
|
11
|
+
gem.description = 'applies sound changes to constructed languages'
|
12
|
+
gem.summary = 'applies diachronic sound changes to constructed languages'
|
13
|
+
gem.homepage = 'http://michaelirick.com'
|
14
|
+
gem.license = 'Nonstandard'
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($RS)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
|
21
|
+
gem.add_dependency 'slop', '~> 3.4'
|
22
|
+
|
23
|
+
gem.add_development_dependency 'simplecov', '~> 0'
|
24
|
+
gem.add_development_dependency 'pry', '~> 0'
|
25
|
+
gem.add_development_dependency 'rake', '~> 0'
|
26
|
+
end
|
data/lib/diachronr.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'diachronr/version'
|
4
|
+
require 'diachronr/rewrite'
|
5
|
+
require 'diachronr/category'
|
6
|
+
require 'diachronr/rule'
|
7
|
+
require 'diachronr/ruleset'
|
8
|
+
|
9
|
+
# module for applying sound changes to constructed languages
|
10
|
+
module Diachronr
|
11
|
+
# Your code goes here...
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Diachronr
|
4
|
+
# rules for rewriting character variations and digraphs
|
5
|
+
class Rewrite
|
6
|
+
attr_accessor :from, :to
|
7
|
+
|
8
|
+
def initialize(rewrite)
|
9
|
+
@from, @to = rewrite.split '|'
|
10
|
+
end # initialize
|
11
|
+
|
12
|
+
def apply(target)
|
13
|
+
target.gsub @from, @to
|
14
|
+
end # apply
|
15
|
+
|
16
|
+
def reverse(target)
|
17
|
+
target.gsub @to, @from
|
18
|
+
end
|
19
|
+
end # class
|
20
|
+
end # module
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Diachronr
|
4
|
+
# rule for applying a single sound change
|
5
|
+
class Rule
|
6
|
+
attr_accessor :from
|
7
|
+
attr_accessor :to
|
8
|
+
attr_accessor :condition
|
9
|
+
|
10
|
+
def initialize(rule)
|
11
|
+
@from, @to, @condition = rule.split '/'
|
12
|
+
end # initialize
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"'#{@from}' > '#{@to}' / '#{@condition}'"
|
16
|
+
end # to_s
|
17
|
+
|
18
|
+
def category?(categories)
|
19
|
+
categories?(from, categories) || categories?(condition, categories)
|
20
|
+
end
|
21
|
+
|
22
|
+
def categories?(value, categories)
|
23
|
+
!get_categories(value, categories).empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_categories(value, categories)
|
27
|
+
categories.select { |c| value.include? c.sign }
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_to(categories, category_index, index)
|
31
|
+
t = get_categories(to, categories)[category_index]
|
32
|
+
return to if t.nil?
|
33
|
+
t.contents[index]
|
34
|
+
end # new_to
|
35
|
+
|
36
|
+
def new_from(category, char)
|
37
|
+
from.gsub category.sign, char
|
38
|
+
end
|
39
|
+
|
40
|
+
def category_rules(categories)
|
41
|
+
rules = []
|
42
|
+
get_categories(from, categories).each_with_index do |cat, i|
|
43
|
+
cat.contents.each_char.with_index do |f, fi|
|
44
|
+
rules << Rule.new(
|
45
|
+
"#{new_from(cat, f)}/#{new_to(categories, i, fi)}/#{condition}"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
rules
|
50
|
+
end
|
51
|
+
|
52
|
+
def condition_rules(categories)
|
53
|
+
rules = []
|
54
|
+
get_categories(condition, categories).each do |cat|
|
55
|
+
cat.contents.each_char do |c|
|
56
|
+
new_condition = condition.gsub cat.sign, c
|
57
|
+
rules << Rule.new("#{from}/#{to}/#{new_condition}")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rules
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge_matches(target, matches)
|
64
|
+
new_target = target.dup
|
65
|
+
matches.each do |match|
|
66
|
+
match.each_char.with_index do |m, i|
|
67
|
+
new_target[i] = m if target[i] != m
|
68
|
+
end
|
69
|
+
end
|
70
|
+
new_target
|
71
|
+
end
|
72
|
+
|
73
|
+
def apply_categories(target, categories)
|
74
|
+
# parse categories, apply each exploded rule to the original target
|
75
|
+
# merge the changes together
|
76
|
+
rules = category_rules(categories) + condition_rules(categories)
|
77
|
+
matches = rules.map { |r| r.apply target, categories: categories }
|
78
|
+
matches.uniq!
|
79
|
+
matches.delete target
|
80
|
+
|
81
|
+
matches.count == 1 ? matches.first : merge_matches(target, matches)
|
82
|
+
end
|
83
|
+
|
84
|
+
def apply(target, options = {})
|
85
|
+
categories = options[:categories] || []
|
86
|
+
return apply_categories target, categories if category? categories
|
87
|
+
|
88
|
+
# construct regex from condition
|
89
|
+
from_condition = @condition.gsub '_', @from
|
90
|
+
to_condition = @condition.gsub '_', @to
|
91
|
+
|
92
|
+
# change word boundaries to regex
|
93
|
+
from_condition = Regexp.new from_condition.gsub('#', '\b')
|
94
|
+
to_condition.delete! '#'
|
95
|
+
|
96
|
+
# split on from_condition and join with to_condition
|
97
|
+
# if you need a limit higher than 10.... nope
|
98
|
+
split_target = target.split from_condition, 10
|
99
|
+
split_target.join to_condition
|
100
|
+
end # apply
|
101
|
+
end # class
|
102
|
+
end # module
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Diachronr
|
6
|
+
# a set of rules, categories, and rewrites applicable to words
|
7
|
+
class RuleSet
|
8
|
+
attr_accessor :rules, :categories, :rewrites, :options
|
9
|
+
|
10
|
+
def initialize(rules, categories, rewrites, options = {})
|
11
|
+
@rules = rules
|
12
|
+
@categories = categories
|
13
|
+
@rewrites = rewrites
|
14
|
+
@options = options
|
15
|
+
end # initialize
|
16
|
+
|
17
|
+
def self.load(filename)
|
18
|
+
options = YAML.load_file filename
|
19
|
+
rules = options['rules'].map { |a| Diachronr::Rule.new(a) }
|
20
|
+
categories = options['categories'].map { |a| Diachronr::Category.new(a) }
|
21
|
+
rewrites = options['rewrites'].map { |a| Diachronr::Rewrite.new(a) }
|
22
|
+
RuleSet.new rules, categories, rewrites, options
|
23
|
+
end
|
24
|
+
|
25
|
+
def apply(target)
|
26
|
+
@rewrites.each do |rewrite|
|
27
|
+
target = rewrite.apply target
|
28
|
+
end # each
|
29
|
+
|
30
|
+
@rules.each do |rule|
|
31
|
+
target = rule.apply target, categories: @categories
|
32
|
+
end # each
|
33
|
+
|
34
|
+
@rewrites.each do |rewrite|
|
35
|
+
target = rewrite.reverse target
|
36
|
+
end # each
|
37
|
+
target
|
38
|
+
end # apply
|
39
|
+
end # class
|
40
|
+
end # module
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'test_helper.rb'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'diachronr'
|
4
|
+
|
5
|
+
class DiachronrTest < Minitest::Test
|
6
|
+
def test_should_create_a_rule
|
7
|
+
r = Diachronr::Rule.new 'a//_'
|
8
|
+
assert_equal r.to_s, "'a' > '' / '_'"
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_apply_simple_rule
|
12
|
+
r = Diachronr::Rule.new 'a//_'
|
13
|
+
assert_equal r.apply('taco'), 'tco'
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_apply_condition
|
17
|
+
r = Diachronr::Rule.new 'a/b/d_e'
|
18
|
+
assert_equal r.apply('daetat'), 'dbetat'
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_apply_word_boundry
|
22
|
+
r = Diachronr::Rule.new 'a/e/_#'
|
23
|
+
assert_equal r.apply('data'), 'date'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_apply_rewrite
|
27
|
+
r = Diachronr::Rewrite.new 'dh|ð'
|
28
|
+
assert_equal r.apply('edhel'), 'eðel'
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_apply_ruleset
|
32
|
+
r = Diachronr::RuleSet.load 'test/fixtures/seonic_to_varag.yml'
|
33
|
+
r.options['seonic'].each do |seonic, varag|
|
34
|
+
assert_equal r.apply(seonic), varag
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
rewrites:
|
2
|
+
- qu|q
|
3
|
+
- th|þ
|
4
|
+
- dh|ð
|
5
|
+
- sh|š
|
6
|
+
- ai|á
|
7
|
+
- au|à
|
8
|
+
- ei|é
|
9
|
+
- eu|è
|
10
|
+
- eo|è
|
11
|
+
- iu|ì
|
12
|
+
- ii|í
|
13
|
+
- oi|ò
|
14
|
+
- ou|ó
|
15
|
+
- ui|ù
|
16
|
+
- uu|ú
|
17
|
+
- h|c
|
18
|
+
categories:
|
19
|
+
- V=aiueo
|
20
|
+
- L=áàéèìíòóùú
|
21
|
+
- C=qwrtypsdfghjkzxcvbnmðþ
|
22
|
+
- A=tpkdbgvþsch
|
23
|
+
- B=þfctpkbdzgg
|
24
|
+
- D=tdðþ
|
25
|
+
- S=szš
|
26
|
+
- U=tpsfhkcþš
|
27
|
+
- F=ua
|
28
|
+
- G=ae
|
29
|
+
- N=âîûêô
|
30
|
+
rules:
|
31
|
+
- a/o/_
|
32
|
+
- u/a/_
|
33
|
+
- o/u/_
|
34
|
+
- i/e/_
|
35
|
+
- á/a/_
|
36
|
+
- à/a/_
|
37
|
+
- é/e/_
|
38
|
+
- è/e/_
|
39
|
+
- ì/i/_
|
40
|
+
- í/i/_
|
41
|
+
- ò/o/_
|
42
|
+
- ó/o/_
|
43
|
+
- ù/u/_
|
44
|
+
- ú/u/_
|
45
|
+
- k/h/#_
|
46
|
+
- t/þ/#_
|
47
|
+
- p/v/#_
|
48
|
+
- c//V_C
|
49
|
+
- sk/š/_
|
50
|
+
- A/B/_
|
51
|
+
- o/a/_
|
52
|
+
- ó/á/_
|
53
|
+
- m/n/_#
|
54
|
+
- m/n/_D
|
55
|
+
- L//_#
|
56
|
+
- en/in/_
|
57
|
+
- z//_#
|
58
|
+
- V//_#
|
59
|
+
- iu/ú/_#
|
60
|
+
- z/r/_
|
61
|
+
- q/ku/_
|
62
|
+
- e/o/_
|
63
|
+
- w/v/#_
|
64
|
+
- w//_i
|
65
|
+
- w//_e
|
66
|
+
- w/v/_a
|
67
|
+
- w/v/_o
|
68
|
+
- w/v/_u
|
69
|
+
- er/ir/_
|
70
|
+
- eD/iD/_
|
71
|
+
- hr/ks/_
|
72
|
+
- è/ú/_
|
73
|
+
- V//_#
|
74
|
+
- é/á/_
|
75
|
+
- F/G/_
|
76
|
+
- o/a/_
|
77
|
+
- r//_#
|
78
|
+
- i/e/U_
|
79
|
+
- oe/oi/_
|
80
|
+
- ao/au/_
|
81
|
+
- mn/nn/_
|
82
|
+
- i/e/_#
|
83
|
+
- aa/ai/_
|
84
|
+
seonic:
|
85
|
+
weson: varan
|
86
|
+
wesic: varag
|
87
|
+
shultus: shelth
|
88
|
+
tumun: demen
|
89
|
+
kousyo: gery
|
90
|
+
korwas: garw
|
91
|
+
menter: mintha
|
92
|
+
avtero: abtha
|
93
|
+
aneo: an # ana
|
94
|
+
alos: al
|
95
|
+
altas: alth
|
96
|
+
nemos: nam
|
97
|
+
saquos: rak
|
98
|
+
asas: a
|
99
|
+
alio: al # al
|
100
|
+
altero: altha
|
101
|
+
sever: raba
|
102
|
+
anvictos: anbath # anbagth
|
103
|
+
an: an
|
104
|
+
eisos: a
|
105
|
+
gonias: kan # kana
|
106
|
+
annos: ann
|
107
|
+
beras: pa
|
108
|
+
ber: pa
|
109
|
+
toquo: dak
|
110
|
+
anveldas: anbalt
|
111
|
+
coro: ga
|
112
|
+
octos: ath
|
113
|
+
abel: apal
|
114
|
+
meilus: mal # male
|
115
|
+
korius: ga # gare
|
116
|
+
kerric: garrag
|
117
|
+
anvo: anb
|
118
|
+
tactus: dath # dathe
|
119
|
+
luukas: lah
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: diachronr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Miker Irick
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: slop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: simplecov
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: applies sound changes to constructed languages
|
70
|
+
email:
|
71
|
+
- michaelirick@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".ruby-version"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- diachronr.gemspec
|
83
|
+
- lib/diachronr.rb
|
84
|
+
- lib/diachronr/category.rb
|
85
|
+
- lib/diachronr/rewrite.rb
|
86
|
+
- lib/diachronr/rule.rb
|
87
|
+
- lib/diachronr/ruleset.rb
|
88
|
+
- lib/diachronr/version.rb
|
89
|
+
- test/diachronr_test.rb
|
90
|
+
- test/fixtures/seonic_to_varag.yml
|
91
|
+
- test/test_helper.rb
|
92
|
+
homepage: http://michaelirick.com
|
93
|
+
licenses:
|
94
|
+
- Nonstandard
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.6.11
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: applies diachronic sound changes to constructed languages
|
116
|
+
test_files:
|
117
|
+
- test/diachronr_test.rb
|
118
|
+
- test/fixtures/seonic_to_varag.yml
|
119
|
+
- test/test_helper.rb
|