humanized 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,122 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This program is free software: you can redistribute it and/or modify
3
+ # it under the terms of the Affero GNU General Public License as published by
4
+ # the Free Software Foundation, either version 3 of the License, or
5
+ # (at your option) any later version.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ #
15
+ # (c) 2011 by Hannes Georg
16
+ #
17
+ require 'facets/array/extract_options.rb'
18
+ require 'facets/hash/deep_merge.rb'
19
+ require 'sync'
20
+ require 'set'
21
+ require 'humanized/compiler.rb'
22
+ require 'humanized/source.rb'
23
+ module Humanized
24
+ # A Humanizer has one simple task: <b>create strings in its language/dialect/locale/whatever!</b>
25
+ #
26
+ # There should be one Humanizer per each configuration, but they can share their three components:
27
+ # * {#source a source} which holds all language data ( mainly strings )
28
+ # * {#compiler a compiler} which compiles the found strings
29
+ # * {#interpolater an interpolater} which holds the methods which can be used in an interpolation
30
+ #
31
+ # The most important method you may use is {#[]}.
32
+ class Humanizer
33
+
34
+ # This is a simple object without public methods. You can use this as a collection for interpolation methods.
35
+ class PrivatObject
36
+ public_instance_methods.each do |meth|
37
+ private meth
38
+ end
39
+
40
+ public :extend
41
+
42
+ end
43
+
44
+ attr_reader :interpolater, :source, :compiler
45
+
46
+ # Creates a new Humanizer
47
+ #
48
+ # @option components [Object] :interpolater This object which has all interpolation methods defined as public methods.
49
+ # @option components [Compiler] :compiler A compiler which can compile strings into procs. (see Compiler)
50
+ # @option components [Source] :source A source which stores translated strings. (see Source)
51
+ def initialize(components = {})
52
+ @interpolater = (components[:interpolater] || PrivatObject.new)
53
+ @compiler = (components[:compiler] || Compiler.new)
54
+ @source = (components[:source] || Source.new)
55
+ end
56
+
57
+ # Creates a new Humanizer which uses the interpolater, compiler and source of this Humanizer unless other values for them were specified.
58
+ # @see #initialize
59
+ def renew(components)
60
+ self.class.new({:interpolater=>@interpolater,:compiler=>@compiler,:source=>@source}.update(components))
61
+ end
62
+
63
+ # Creates a String from the input. This will be the most used method in application code.
64
+ # It expects a {Scope} as argument. Anything that is not a {Scope} will be converted into a {Scope} using the "_"-method.
65
+ # This enables you to pass any object to this method. The result is mainly determined by result of the "_"-method.
66
+ # For
67
+ #
68
+ # @param [Scope, #_, Object] *args
69
+ # @return [String]
70
+ def [](*args)
71
+ it = args._
72
+
73
+ vars = it.variables
74
+ default = it.default
75
+ result = @source.get(it, default)
76
+ result = default unless result.kind_of? String
77
+ if result.kind_of? String
78
+ return interpolate(result,vars)
79
+ elsif default.__id__ != result.__id__
80
+ warn "[] should be only used for strings. For anything else use get."
81
+ end
82
+ return result
83
+ end
84
+
85
+ # This is a wrapper for @source.get.
86
+ # The only thing it does additionally is converting all params into a Scope.
87
+ # @see Source#get
88
+ def get(base,*rest)
89
+ it = base._(*rest)
90
+ return @source.get(it, it.default)
91
+ end
92
+
93
+ # Stores a translation
94
+ def []=(it, *rest)
95
+ last = rest.pop
96
+ @source.store(it._(*rest).first,last)
97
+ end
98
+
99
+ # This is an alias for @source.package
100
+ # @see Source#package
101
+ def package(*args,&block)
102
+ @source.package(*args,&block)
103
+ end
104
+
105
+ # This is an alias for @source.load
106
+ # @see Source#load
107
+ def load(*args,&block)
108
+ @source.load(*args,&block)
109
+ end
110
+
111
+ # This is an alias for @source.<<
112
+ # @see Source#<<
113
+ def <<(x)
114
+ @source << x
115
+ end
116
+
117
+ def interpolate(str,vars={})
118
+ @compiler.compile(str).call(self,@interpolater,vars)
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This program is free software: you can redistribute it and/or modify
3
+ # it under the terms of the Affero GNU General Public License as published by
4
+ # the Free Software Foundation, either version 3 of the License, or
5
+ # (at your option) any later version.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ #
15
+ # (c) 2011 by Hannes Georg
16
+ #
17
+ module Humanized
18
+
19
+ module Conjunctions
20
+
21
+ def and(humanizer, *args)
22
+ args = args.flatten
23
+ last = args.pop
24
+ return [args.join(', '), last].join(' '+humanizer[:and]+' ')
25
+ end
26
+
27
+ def or(humanizer, *args)
28
+ args = args.flatten
29
+ last = args.pop
30
+ return [args.join(', '), last].join(' '+humanizer[:or]+' ')
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This program is free software: you can redistribute it and/or modify
3
+ # it under the terms of the Affero GNU General Public License as published by
4
+ # the Free Software Foundation, either version 3 of the License, or
5
+ # (at your option) any later version.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ #
15
+ # (c) 2011 by Hannes Georg
16
+ #
17
+
18
+ module Humanized
19
+ module Date
20
+
21
+ def date(humanizer, date, format = 'default')
22
+ if format == 'default'
23
+ it = date._(:format,:default)
24
+ else
25
+ it = date._.format( format._ | :default._ )
26
+ end
27
+ f = humanizer.get(it)
28
+ if f.kind_of? String
29
+ return date.strftime( f )
30
+ end
31
+ warn 'Unable to find Date format: #{it.inspect}.'
32
+ return ''
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,83 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This program is free software: you can redistribute it and/or modify
3
+ # it under the terms of the Affero GNU General Public License as published by
4
+ # the Free Software Foundation, either version 3 of the License, or
5
+ # (at your option) any later version.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ #
15
+ # (c) 2011 by Hannes Georg
16
+ #
17
+ require 'humanized/interpolation/kng.rb'
18
+ module Humanized
19
+ module English
20
+
21
+ module Articles
22
+
23
+ def a(humanizer, *args)
24
+ Wrapper.wrap(args) do |t|
25
+ fs = first_sound(humanizer, t)
26
+ s = t.to_s
27
+ if( fs.nil? )
28
+ fs = guess_first_sound(s)
29
+ end
30
+ (fs == :vowel ? 'an' : 'a' ) + ' ' + s
31
+ end
32
+ end
33
+
34
+ def the(humanizer, *args)
35
+ Wrapper.wrap(args) do |t|
36
+ 'the ' + t.to_s
37
+ end
38
+ end
39
+
40
+ def no(humanizer, *args)
41
+ Wrapper.wrap(args) do |t|
42
+ 'no ' + t.to_s
43
+ end
44
+ end
45
+
46
+ def some(humanizer, *args)
47
+ Wrapper.wrap(args) do |t|
48
+ 'some ' + t.to_s
49
+ end
50
+ end
51
+
52
+ protected
53
+ def first_sound(humanizer, x)
54
+ return humanizer.get( x._(:first_sound) )
55
+ end
56
+
57
+ def guess_first_sound(s)
58
+ return :consonant
59
+ end
60
+
61
+ end
62
+
63
+ include KNG
64
+ include Articles
65
+
66
+ KASUS = [
67
+ 'nominativ'.freeze,
68
+ 'genitiv'.freeze
69
+ ].freeze
70
+
71
+ NUMERUS = [
72
+ 'singular'.freeze,
73
+ 'plural'.freeze
74
+ ].freeze
75
+
76
+ GENUS = [
77
+ 'neutral'.freeze,
78
+ 'male'.freeze,
79
+ 'female'.freeze
80
+ ].freeze
81
+
82
+ end
83
+ end
@@ -0,0 +1,74 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This program is free software: you can redistribute it and/or modify
3
+ # it under the terms of the Affero GNU General Public License as published by
4
+ # the Free Software Foundation, either version 3 of the License, or
5
+ # (at your option) any later version.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ #
15
+ # (c) 2011 by Hannes Georg
16
+ #
17
+ require 'humanized/interpolation/kng.rb'
18
+ module Humanized
19
+ module German
20
+
21
+ module Articles
22
+
23
+ ArticleScope = Scope::Meta.articles
24
+
25
+ def a(humanizer, *args)
26
+ Wrapper.wrap(args) do |t|
27
+ humanizer[ArticleScope.indefinite.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
28
+ end
29
+ end
30
+
31
+ def the(humanizer, *args)
32
+ Wrapper.wrap(args) do |t|
33
+ humanizer[ArticleScope.definite.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
34
+ end
35
+ end
36
+
37
+ def some(humanizer, *args)
38
+ Wrapper.wrap(args) do |t|
39
+ humanizer[ArticleScope.partitive.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
40
+ end
41
+ end
42
+
43
+ def none(humanizer, *args)
44
+ Wrapper.wrap(args) do |t|
45
+ humanizer[ArticleScope.negative.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ include Articles
52
+
53
+ include KNG
54
+
55
+ KASUS = [
56
+ 'nominativ'.freeze,
57
+ 'genitiv'.freeze,
58
+ 'dativ'.freeze,
59
+ 'akkusativ'.freeze
60
+ ].freeze
61
+
62
+ NUMERUS = [
63
+ 'singular'.freeze,
64
+ 'plural'.freeze
65
+ ].freeze
66
+
67
+ GENUS = [
68
+ 'neutral'.freeze,
69
+ 'male'.freeze,
70
+ 'female'.freeze
71
+ ].freeze
72
+
73
+ end
74
+ end
@@ -0,0 +1,217 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This program is free software: you can redistribute it and/or modify
3
+ # it under the terms of the Affero GNU General Public License as published by
4
+ # the Free Software Foundation, either version 3 of the License, or
5
+ # (at your option) any later version.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ #
15
+ # (c) 2011 by Hannes Georg
16
+ #
17
+ require 'set'
18
+ require 'abbrev'
19
+ require 'facets/kernel/meta_class.rb'
20
+ require "humanized/interpolation/conjunctions"
21
+ require 'humanized/wrapper'
22
+ module Humanized
23
+
24
+ module KNG
25
+
26
+ class KNGWrapper < Humanized::Wrapper
27
+
28
+ attr_reader :kng_kasus, :kng_numerus, :kng_genus
29
+
30
+ def initialize(object, humanizer, kasus, numerus, genus=nil)
31
+ @kng_kasus = kasus
32
+ @kng_numerus = numerus
33
+ @kng_genus = genus
34
+ @kng_humanizer = humanizer
35
+ self.__setobj__(object)
36
+ end
37
+
38
+ def self.wrap(args, *rest)
39
+ a = args.flatten.map{|o|
40
+ self.new(o,*rest)
41
+ }
42
+ return a.size == 1 ? a[0] : a
43
+ end
44
+
45
+ def to_s
46
+ if @kng_genus
47
+ return @kng_humanizer[__getobj__._.optionally(@kng_genus)._(@kng_numerus, @kng_kasus)]
48
+ else
49
+ return @kng_humanizer[__getobj__._(@kng_numerus, @kng_kasus)]
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ def g(humanizer, genus, *args)
56
+ if args.size == 3
57
+ # male, female, neutral
58
+ genus = x_to_genus(humanizer, genus)
59
+ a = [:male,:female,:neutral].zip(args)
60
+ if genus.kind_of? Set
61
+ return genus.map{|g| a.assoc(g)[1] }
62
+ end
63
+ return a.assoc(genus)[1]
64
+ end
65
+ end
66
+
67
+ def n(humanizer, numerus, *args)
68
+ if args.size == 2
69
+ # singular, plural
70
+ return args[ x_to_numerus(humanizer, numerus) == :singular ? 0 : 1 ]
71
+ elsif args.size == 1
72
+ return KNGWrapper.wrap(args, humanizer, meta_class.const_get(:KASUS).first.to_sym, x_to_numerus(humanizer, numerus))
73
+ end
74
+ end
75
+
76
+ def kn(humanizer, kasus, numerus, *args)
77
+ if args.size == 2
78
+ # singular, plural
79
+ return args[ x_to_numerus(humanizer, numerus) == :singular ? 0 : 1 ]
80
+ elsif args.size == 1
81
+ return KNGWrapper.wrap(args, humanizer, x_to_kasus(humanizer, kasus), x_to_numerus(humanizer, numerus))
82
+ end
83
+ end
84
+
85
+
86
+ def kng(humanizer, kasus, numerus, genus,*args)
87
+ if args.size == 2
88
+ # singular, plural
89
+ return args[ x_to_numerus(humanizer, numerus) == :singular ? 0 : 1 ]
90
+ elsif args.size == 1
91
+ return KNGWrapper.wrap(args, humanizer, x_to_kasus(humanizer, kasus), x_to_numerus(humanizer, numerus), x_to_genus(humanizer, genus))
92
+ end
93
+ end
94
+
95
+ def kongruent(humanizer, from, *args)
96
+ return KNGWrapper.wrap(args, humanizer, x_to_kasus(humanizer, from), x_to_numerus(humanizer, from), x_to_genus(humanizer, from))
97
+ end
98
+
99
+ protected
100
+
101
+ def abbrev_kasus
102
+ return @abbrev_kasus if @abbrev_kasus
103
+ @abbrev_kasus ||= Hash[*meta_class.const_get(:KASUS).abbrev.map{|(a,b)| [a,b.to_sym]}.flatten(1)]
104
+ @abbrev_kasus.default = meta_class.const_get(:KASUS).first.to_sym
105
+ return @abbrev_kasus
106
+ end
107
+
108
+ def abbrev_numerus
109
+ return @abbrev_numerus if @abbrev_numerus
110
+ @abbrev_numerus ||= Hash[*meta_class.const_get(:NUMERUS).abbrev.map{|(a,b)| [a,b.to_sym]}.flatten(1)]
111
+ @abbrev_numerus.default = meta_class.const_get(:NUMERUS).first.to_sym
112
+ return @abbrev_numerus
113
+ end
114
+
115
+ def abbrev_genus
116
+ return @abbrev_genus if @abbrev_genus
117
+ @abbrev_genus ||= Hash[*meta_class.const_get(:GENUS).abbrev.map{|(a,b)| [a,b.to_sym]}.flatten(1)]
118
+ @abbrev_genus.default = meta_class.const_get(:GENUS).first.to_sym
119
+ return @abbrev_genus
120
+ end
121
+
122
+ def merge_genus(a,b)
123
+ if a.kind_of? Set
124
+ if b.kind_of? Set
125
+ return a + b
126
+ else
127
+ return a + [b]
128
+ end
129
+ else
130
+ if b.kind_of? Set
131
+ return b + [a]
132
+ else
133
+ return Set.new([a,b])
134
+ end
135
+ end
136
+ end
137
+
138
+ def x_to_genus(humanizer, x)
139
+ if x.respond_to? :kng_genus
140
+ return x.kng_genus if x.kng_genus
141
+ end
142
+ if x.kind_of? HasNaturalGenus
143
+ return x.genus
144
+ end
145
+ if x.kind_of? Array
146
+ # TODO: this is inefficient...
147
+ # IDEA 1: plug in something like Array.of(...)
148
+ s = Set.new
149
+ x.each do |o|
150
+ s = merge_genus( s, x_to_genus(humanizer, o) )
151
+ if s.size == 3
152
+ break
153
+ end
154
+ end
155
+ return s
156
+ end
157
+ if x.kind_of? String
158
+ return abbrev_genus[x]
159
+ end
160
+ genus = humanizer.get(x._(:genus))
161
+ if genus.kind_of? Symbol
162
+ return genus
163
+ else
164
+ return :neutral
165
+ end
166
+ end
167
+
168
+ def x_to_kasus(humanizer, x)
169
+ if x.respond_to? :kng_kasus
170
+ return x.kng_kasus
171
+ end
172
+ i = x.to_i
173
+ c = meta_class.const_get :KASUS
174
+ if i > 0 and i <= c.size
175
+ return c[i-1].to_sym
176
+ end
177
+ return abbrev_kasus[x]
178
+ end
179
+
180
+ def x_to_numerus(humanizer, x)
181
+ if x.respond_to? :kng_numerus
182
+ return x.kng_numerus
183
+ end
184
+ # seriously: this sucks!
185
+ i = x_to_i(humanizer, x)
186
+ if i.nil? and x.kind_of? String
187
+ return abbrev_numerus[x]
188
+ end
189
+ if i
190
+ if i == 1
191
+ return :singular
192
+ else
193
+ return :plural
194
+ end
195
+ end
196
+ numerus = humanizer.get(x._(:numerus))
197
+ if numerus.kind_of? Symbol
198
+ return numerus
199
+ else
200
+ return :singular
201
+ end
202
+ end
203
+
204
+ def x_to_i(humanizer, x)
205
+ return nil if x.kind_of?(String) and x !~ /\d+/
206
+ unless x.respond_to? :to_i
207
+ unless x.respond_to?(:size)
208
+ return nil
209
+ end
210
+ return x.size
211
+ end
212
+ return x.to_i
213
+ end
214
+
215
+ end
216
+
217
+ end