spanish 0.0.2 → 0.0.3

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.
@@ -21,8 +21,12 @@ module Spanish
21
21
  # Get an array of Phonology::Sounds from the string.
22
22
  def get_sounds(string, *rules)
23
23
  sequence = Orthography.translator.translate(string)
24
- Phonology.rules.values.each do |rule|
25
- sequence.apply_rule!(rule)
24
+ Syllabifier.syllabify(sequence)
25
+ Phonology.general_rules.values.each do |rule|
26
+ rule.apply(sequence)
27
+ end
28
+ rules.each do |rule|
29
+ Phonology.optional_rules[rule.to_sym].apply(sequence)
26
30
  end
27
31
  sequence
28
32
  end
@@ -32,8 +36,16 @@ module Spanish
32
36
  #
33
37
  # Spanish.get_ipa("chavo")
34
38
  # # => 't͡ʃaβo
35
- def get_ipa(string)
36
- get_sounds(string).to_s
39
+ def get_ipa(string, *rules)
40
+ get_sounds(string, *rules).to_s
41
+ end
42
+
43
+ def get_syllables(string, *rules)
44
+ get_sounds(string, *rules).map(&:syllable).uniq
37
45
  end
38
46
 
47
+ def get_syllables_ipa(string, *rules)
48
+ syllables = get_syllables(string, *rules)
49
+ syllables.map {|s| syllables.length == 1 ? s.to_s(false) : s.to_s }.join(" ")
50
+ end
39
51
  end
@@ -1,13 +1,9 @@
1
1
  # encoding: utf-8
2
2
  module Spanish
3
3
  module Orthography
4
-
5
4
  extend self
6
-
7
5
  LETTERS = /ch|ll|ñ|á|é|í|ó|ú|ü|[\w]/
8
-
9
6
  SCANNER = lambda {|string| string.downcase.scan(/rr|ch|ll|ñ|á|é|í|ó|ú|ü|\w/)}
10
-
11
7
  SOUNDS = ::Phonology::Inventory.from_ipa(
12
8
  "m", "n", "ɲ", "ŋ", "p", "b", "t", "d", "k", "ɡ", "β", "f", "v", "ð", "s",
13
9
  "z", "ʒ", "ʝ", "x", "ɣ", "j", "r", "ɾ", "l", "w", "i", "u", "e", "o", "a",
@@ -78,9 +74,8 @@ module Spanish
78
74
  if initial?
79
75
  get(:unvoiced, :velar, :fricative)
80
76
  else
81
- [get(:unvoiced, :velar, :plosive), Phonology::Sound.new("s")]
77
+ [get(:unvoiced, :velar, :plosive), ::Phonology::Sound.new("s")]
82
78
  end
83
-
84
79
  when "y"
85
80
  if initial? && final?
86
81
  get(:close, :front)
@@ -93,7 +88,10 @@ module Spanish
93
88
  elsif !precedes(vowel)
94
89
  get(:palatal, :approximant)
95
90
  end
96
- when "z" then get(:unvoiced, :dental, :fricative)
91
+ when "z"
92
+ # Spanish final "z" indicates stress: i.e. "madures" vs. "madurez"
93
+ last_sound.hint(:primary_stress) if final? and follows(vowel)
94
+ get(:unvoiced, :dental, :fricative)
97
95
  end
98
96
  }
99
97
 
@@ -106,7 +104,5 @@ module Spanish
106
104
  orth.rules = RULES
107
105
  orth
108
106
  end
109
-
110
107
  end
111
-
112
- end
108
+ end
@@ -5,9 +5,10 @@ module Spanish
5
5
 
6
6
  extend self
7
7
 
8
- attr_reader :rules
8
+ attr_reader :general_rules
9
+ attr_reader :optional_rules
9
10
 
10
- @rules = {
11
+ @general_rules = {
11
12
  :sprinantization => ::Phonology::Rule.new {
12
13
  if voiced? and plosive? and !initial? and precedes(:vocoid) and !follows(:nasal)
13
14
  if non_coronal?
@@ -17,11 +18,42 @@ module Spanish
17
18
  end
18
19
  end
19
20
  },
21
+ :nasal_assimilation => ::Phonology::Rule.new {
22
+ add :bilabial if nasal? and precedes :bilabial
23
+ }
24
+ }
25
+ @optional_rules = {
20
26
  :seseo => ::Phonology::Rule.new {
21
27
  add :alveolar if dental? and unvoiced?
22
28
  },
23
29
  :voicing => ::Phonology::Rule.new {
24
30
  voice if alveolar? and fricative? and precedes(:voiced, :non_vocoid)
31
+ },
32
+ :aspiration => ::Phonology::Rule.new {
33
+ if syllable_final? and alveolar? and fricative? and follows(:vocoid)
34
+ devoice
35
+ add :glottal
36
+ add! :approximant
37
+ end
38
+ },
39
+ :yeismo => ::Phonology::Rule.new {
40
+ if palatal? and (lateral_approximant? or fricative?)
41
+ add :palatal, :fricative
42
+ end
43
+ },
44
+ :lleismo => ::Phonology::Rule.new {
45
+ add :lateral_approximant if (palatal? and fricative?)
46
+ },
47
+ :zheismo => ::Phonology::Rule.new {
48
+ if palatal? and (lateral_approximant? or fricative?)
49
+ add :postalveolar, :fricative
50
+ end
51
+ },
52
+ :sheismo => ::Phonology::Rule.new {
53
+ if palatal? and (lateral_approximant? or fricative?)
54
+ add :postalveolar, :fricative
55
+ delete :voiced
56
+ end
25
57
  }
26
58
  }
27
59
 
@@ -1,37 +1,5 @@
1
- # @TODO
2
- # Problem words: insubstancialidad, descouella
3
1
  module Spanish
4
- class Syllable
5
-
6
- attr_accessor :onset, :coda, :nucleus, :stress
7
-
8
- def initialize(sound = nil)
9
- @onset = []
10
- @nucleus = []
11
- @coda = []
12
- add sound if sound
13
- end
14
-
15
- def to_a
16
- [onset, rime].flatten
17
- end
18
-
19
- def valid?
20
- !nucleus.empty?
21
- end
22
-
23
- def rime
24
- [nucleus, coda]
25
- end
26
-
27
- def to_s
28
- string = to_a.map(&:symbol).join
29
- (stress ? "\u02c8" : "") + string
30
- end
31
-
32
- def wants?(sound)
33
- onset_wants?(sound) or nucleus_wants?(sound) or coda_wants?(sound)
34
- end
2
+ class Syllable < ::Phonology::Syllable
35
3
 
36
4
  def onset_wants?(sound)
37
5
  if !nucleus.empty? || sound.vocalic?
@@ -58,6 +26,8 @@ module Spanish
58
26
  def coda_wants?(sound)
59
27
  if nucleus.empty?
60
28
  false
29
+ elsif !coda.empty?
30
+ false if coda.last.approximant?
61
31
  else
62
32
  # Codas don't want a rising dipthong but will accept one at the end of words.
63
33
  sound.consonantal? && !(sound.approximant? && sound.palatal?)
@@ -66,19 +36,15 @@ module Spanish
66
36
 
67
37
  def <<(sound)
68
38
  @stress = true if sound.hints.include?(:primary_stress)
69
- if onset_wants?(sound)
70
- @onset << sound
71
- elsif nucleus_wants?(sound)
72
- @nucleus << sound
73
- else
74
- @coda << sound
75
- end
39
+ super
76
40
  end
77
- alias add <<
41
+ end
78
42
 
79
- def empty?
80
- onset.empty? && nucleus.empty? && coda.empty?
81
- end
43
+ class Syllabifier
44
+
45
+ include Enumerable
46
+
47
+ attr :index, :sounds, :syllable
82
48
 
83
49
  def self.apply_stress(syllables)
84
50
  if syllables.detect {|s| s.stress}
@@ -98,78 +64,71 @@ module Spanish
98
64
 
99
65
  def self.syllabify(arg)
100
66
  arg = arg.kind_of?(String) ? Spanish.get_sounds(arg) : arg
101
- apply_stress(Syllables.new(arg).entries)
67
+ apply_stress(new(arg).entries)
102
68
  end
103
69
 
104
- class Syllables
105
-
106
- include Enumerable
107
-
108
- attr :index, :sounds, :syllable
109
-
110
- def initialize(sounds)
111
- @sounds = sounds
112
- end
113
-
114
- def each(&block)
115
- begin
116
- sounds.each_index { |i| @index = i; append or do_yield(&block) }
117
- do_yield(&block)
118
- ensure
119
- @index = 0
120
- @syllable = nil
121
- end
122
- end
123
-
124
- private
70
+ def initialize(sounds)
71
+ @sounds = sounds
72
+ end
125
73
 
126
- def do_yield(&block)
127
- yield syllable
128
- @syllable = Syllable.new(curr)
74
+ def each(&block)
75
+ begin
76
+ sounds.each_index { |i| @index = i; append or do_yield(&block) }
77
+ do_yield(&block)
78
+ ensure
79
+ @index = 0
80
+ @syllable = nil
129
81
  end
82
+ end
130
83
 
131
- def syllable
132
- @syllable ||= Syllable.new
133
- end
84
+ private
134
85
 
135
- def append
136
- return if !curr
137
- # Final consonantal has nowhere else to go.
138
- if !nex && curr.consonantal?
139
- syllable << curr
140
- # If there's no room in the syllable, we're forced to start a new one.
141
- elsif !syllable.wants? curr
142
- false
143
- # Spanish has a strong aversion to syllable-initial consonant clusters
144
- # beginning with "s".
145
- elsif syllable.wants?(curr) && nex && curr.alveolar? && curr.fricative? && nex.non_vocoid?
146
- syllable << curr
147
- # Otherwise, the preference is to be the onset of a new syllable. This
148
- # is only possible when the syllable we would create has sonority rising
149
- # towards the nucleus.
150
- elsif nex && syllable.valid? && (nex.sonority - curr.sonority > 1)
151
- false
152
- # Default action is to append to current syllable.
153
- else
154
- syllable << curr
155
- end
156
- end
86
+ def do_yield(&block)
87
+ yield syllable
88
+ # For final syllables, this will only create a new syllable for one-vowel final syllables,
89
+ # Honestly, I'm a little lost as to why that happens, probably need a code improvement
90
+ # in some other place.
91
+ @syllable = Syllable.new(curr) unless !nex && curr.syllable
92
+ end
157
93
 
158
- def curr
159
- @sounds[index]
160
- end
94
+ def syllable
95
+ @syllable ||= Syllable.new
96
+ end
161
97
 
162
- def prev
163
- @sounds[index - 1] unless index == 0
98
+ def append
99
+ return if !curr
100
+ # Final consonantal has nowhere else to go.
101
+ if !nex && curr.consonantal?
102
+ syllable << curr
103
+ # If there's no room in the syllable, we're forced to start a new one.
104
+ elsif !syllable.wants? curr
105
+ false
106
+ # Spanish has a strong aversion to syllable-initial consonant clusters
107
+ # beginning with "s".
108
+ elsif syllable.wants?(curr) && nex && curr.alveolar? && curr.fricative? && nex.non_vocoid?
109
+ syllable << curr
110
+ # Otherwise, the preference is to be the onset of a new syllable. This
111
+ # is only possible when the syllable we would create has sonority rising
112
+ # towards the nucleus.
113
+ elsif nex && syllable.valid? && (nex.sonority - curr.sonority > 1)
114
+ false
115
+ # Default action is to append to current syllable.
116
+ else
117
+ syllable << curr
164
118
  end
119
+ end
165
120
 
166
- def nex
167
- @sounds[index + 1]
168
- end
121
+ def curr
122
+ @sounds[index]
123
+ end
169
124
 
125
+ def prev
126
+ @sounds[index - 1] unless index == 0
170
127
  end
171
128
 
129
+ def nex
130
+ @sounds[index + 1]
131
+ end
172
132
 
173
133
  end
174
-
175
134
  end
@@ -1,3 +1,3 @@
1
1
  module Spanish
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -5,7 +5,7 @@ class PhonologyTest < Test::Unit::TestCase
5
5
 
6
6
  test "c as s or k" do
7
7
  assert_sound "kasa", "casa"
8
- assert_sound "bisi", "bici"
8
+ assert_sound "biθi", "bici"
9
9
  assert_sound "fɾanko", "franco"
10
10
  end
11
11
 
@@ -30,13 +30,13 @@ class PhonologyTest < Test::Unit::TestCase
30
30
  test "y" do
31
31
  assert_sound "i", "y"
32
32
  assert_sound "kaʝo", "cayó"
33
- assert_sound "iɣwasu", "yguazú"
33
+ assert_sound "iɣwaθu", "yguazú"
34
34
  assert_sound "doj", "doy"
35
35
  end
36
36
 
37
37
  test "voicing" do
38
- assert_sound "razɣo", "rasgo"
39
- assert_sound "xazmin", "jazmín"
38
+ assert_sound "rasɣo", "rasgo"
39
+ assert_sound "xaθmin", "jazmín"
40
40
  end
41
41
 
42
42
  test "trilled r and flap r" do
@@ -3,41 +3,40 @@ require File.expand_path("../test_helper", __FILE__)
3
3
 
4
4
  class SyllabificationTest < Test::Unit::TestCase
5
5
 
6
- include Phonology
7
6
  include Spanish
8
7
 
9
8
  test "should add consonant to empty onset" do
10
9
  s = Syllable.new
11
- assert s.onset_wants? Sound.new("t")
12
- assert s.onset_wants? Sound.new("l")
13
- assert s.onset_wants? Sound.new("w")
10
+ assert s.onset_wants? Phonology::Sound.new("t")
11
+ assert s.onset_wants? Phonology::Sound.new("l")
12
+ assert s.onset_wants? Phonology::Sound.new("w")
14
13
  end
15
14
 
16
15
  test "should not add vowel to empty onsent" do
17
16
  s = Syllable.new
18
- assert !s.onset_wants?(Sound.new("o"))
17
+ assert !s.onset_wants?(Phonology::Sound.new("o"))
19
18
  end
20
19
 
21
20
  test "can append consonant to onset if liquid" do
22
21
  s = Syllable.new
23
- s.onset << Sound.new("t")
24
- assert s.onset_wants? Sound.new("l")
25
- assert s.onset_wants? Sound.new("ɾ")
22
+ s.onset << Phonology::Sound.new("t")
23
+ assert s.onset_wants? Phonology::Sound.new("l")
24
+ assert s.onset_wants? Phonology::Sound.new("ɾ")
26
25
  end
27
26
 
28
27
  test "can append consonant to onset if approximant" do
29
28
  s = Syllable.new
30
- s.onset << Sound.new("k")
31
- assert s.onset_wants? Sound.new("w")
29
+ s.onset << Phonology::Sound.new("k")
30
+ assert s.onset_wants? Phonology::Sound.new("w")
32
31
  end
33
32
 
34
33
  test "can not append sound to onset if non-liquid and non-approximant" do
35
34
  s = Syllable.new
36
- s.onset << Sound.new("k")
37
- assert !s.onset_wants?(Sound.new("n"))
38
- assert !s.onset_wants?(Sound.new("r"))
39
- assert !s.onset_wants?(Sound.new("s"))
40
- assert !s.onset_wants?(Sound.new("a"))
35
+ s.onset << Phonology::Sound.new("k")
36
+ assert !s.onset_wants?(Phonology::Sound.new("n"))
37
+ assert !s.onset_wants?(Phonology::Sound.new("r"))
38
+ assert !s.onset_wants?(Phonology::Sound.new("s"))
39
+ assert !s.onset_wants?(Phonology::Sound.new("a"))
41
40
  end
42
41
 
43
42
  end
@@ -1,3 +1,6 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup
1
4
  require "test/unit"
2
5
  require File.expand_path("../../lib/spanish", __FILE__)
3
6
  include Spanish
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Norman Clarke
@@ -14,13 +14,14 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-20 00:00:00 -03:00
17
+ date: 2010-07-09 00:00:00 -03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: phonology
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
24
25
  requirements:
25
26
  - - ">="
26
27
  - !ruby/object:Gem::Version
@@ -61,6 +62,7 @@ rdoc_options: []
61
62
  require_paths:
62
63
  - lib
63
64
  required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
64
66
  requirements:
65
67
  - - ">="
66
68
  - !ruby/object:Gem::Version
@@ -69,6 +71,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
71
  - 9
70
72
  version: "1.9"
71
73
  required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
72
75
  requirements:
73
76
  - - ">="
74
77
  - !ruby/object:Gem::Version
@@ -78,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
81
  requirements: []
79
82
 
80
83
  rubyforge_project: "[none]"
81
- rubygems_version: 1.3.6
84
+ rubygems_version: 1.3.7
82
85
  signing_key:
83
86
  specification_version: 3
84
87
  summary: Spanish phonology, orthography and grammar library for Ruby.