humanized 0.0.1.alpha

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.
@@ -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