humanized 0.0.1.alpha → 0.0.1

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,71 @@
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
+ class Interpolater
19
+
20
+ UNCHANGED_METHODS = Set.new([:__send__,:object_id])
21
+ PRIVATE_METHODS = Set.new([:extend,:send,:eval,:instance_exec,:instance_eval, :respond_to? ,:__id__,:method])
22
+
23
+ class LockedDown
24
+ public_instance_methods.each do |meth|
25
+ if UNCHANGED_METHODS.include? meth.to_sym
26
+ next
27
+ elsif PRIVATE_METHODS.include? meth.to_sym
28
+ private meth
29
+ else
30
+ undef_method meth
31
+ end
32
+ end
33
+
34
+ def lock!
35
+ m = method(:send)
36
+ class << self
37
+ undef :lock!
38
+ end
39
+ return m
40
+ end
41
+ end
42
+
43
+ PRIVATE_METHODS.each do |meth|
44
+ class_eval(<<RB)
45
+ alias_method :real_#{meth}, #{meth.inspect}
46
+
47
+ def #{meth.to_s}(*args,&block)
48
+ @masterkey.send(#{meth.inspect},*args,&block)
49
+ end
50
+ RB
51
+ end
52
+
53
+ def initialize
54
+ @object = LockedDown.new
55
+ @masterkey = @object.lock!
56
+ end
57
+
58
+ def <<(mod)
59
+ @masterkey.call(:extend, mod)
60
+ return self
61
+ end
62
+
63
+ def object; @object ; end
64
+
65
+ def inspect
66
+ "#<#{self.class.name}:#{self.object_id.to_s}>"
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -21,12 +21,18 @@ module Conjunctions
21
21
  def and(humanizer, *args)
22
22
  args = args.flatten
23
23
  last = args.pop
24
+ if args.size == 0
25
+ return last.to_s
26
+ end
24
27
  return [args.join(', '), last].join(' '+humanizer[:and]+' ')
25
28
  end
26
29
 
27
30
  def or(humanizer, *args)
28
31
  args = args.flatten
29
32
  last = args.pop
33
+ if args.size == 0
34
+ return last.to_s
35
+ end
30
36
  return [args.join(', '), last].join(' '+humanizer[:or]+' ')
31
37
  end
32
38
 
@@ -19,18 +19,26 @@ module Humanized
19
19
  module Date
20
20
 
21
21
  def date(humanizer, date, format = 'default')
22
- if format == 'default'
22
+ if format == 'default' or format.nil?
23
23
  it = date._(:format,:default)
24
24
  else
25
+ format = format.to_sym
25
26
  it = date._.format( format._ | :default._ )
26
27
  end
27
28
  f = humanizer.get(it)
29
+ if humanizer.respond_to? :calendar
30
+
31
+ return humanizer.calendar.format( f )
32
+
33
+ end
28
34
  if f.kind_of? String
29
35
  return date.strftime( f )
30
36
  end
31
- warn 'Unable to find Date format: #{it.inspect}.'
37
+ if humanizer.logger
38
+ humanizer.logger.error "Unable to find Date format: #{it.inspect}."
39
+ end
32
40
  return ''
33
41
  end
34
42
 
35
43
  end
36
- end
44
+ end
@@ -14,16 +14,16 @@
14
14
  #
15
15
  # (c) 2011 by Hannes Georg
16
16
  #
17
-
17
+ require 'humanized/wrapper'
18
18
  module Humanized
19
+ module Default
19
20
 
20
- # A Reference can be used to redirect lookups for certain paths.
21
- class Ref < Array
22
-
23
- def inspect
24
- '!ref'+super
25
- end
26
-
21
+ def capitalize(humanizer, *str)
22
+ return Humanized::Wrapper.wrap(*str) do |s|
23
+ s[0...1].upcase + s[1..-1]
27
24
  end
28
-
25
+ end
26
+
27
+
28
+ end
29
29
  end
@@ -14,35 +14,37 @@
14
14
  #
15
15
  # (c) 2011 by Hannes Georg
16
16
  #
17
+ require 'humanized'
18
+ require 'humanized/query'
17
19
  require 'humanized/interpolation/kng.rb'
18
20
  module Humanized
19
21
  module German
20
22
 
21
23
  module Articles
22
24
 
23
- ArticleScope = Scope::Meta.articles
25
+ ArticleQuery = Query::Meta.articles
24
26
 
25
27
  def a(humanizer, *args)
26
28
  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
29
+ humanizer[ArticleQuery.indefinite.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
28
30
  end
29
31
  end
30
32
 
31
33
  def the(humanizer, *args)
32
34
  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
35
+ humanizer[ArticleQuery.definite.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
34
36
  end
35
37
  end
36
38
 
37
39
  def some(humanizer, *args)
38
40
  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
41
+ humanizer[ArticleQuery.partitive.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
40
42
  end
41
43
  end
42
44
 
43
45
  def none(humanizer, *args)
44
46
  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
47
+ humanizer[ArticleQuery.negative.optionally(x_to_genus(humanizer, t))._(x_to_numerus(humanizer, t), x_to_kasus(humanizer, t))] + ' ' + t.to_s
46
48
  end
47
49
  end
48
50
 
@@ -71,4 +73,4 @@ module German
71
73
  ].freeze
72
74
 
73
75
  end
74
- end
76
+ end
@@ -43,11 +43,17 @@ module KNG
43
43
  end
44
44
 
45
45
  def to_s
46
+ return @kng_humanizer.get(__getobj__._(__generate_paths__))
47
+ end
48
+
49
+ protected
50
+
51
+ def __generate_paths__
52
+ a = Query::Root
46
53
  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)]
54
+ a = a.optionally(@kng_genus)
50
55
  end
56
+ return a.optionally(@kng_numerus).optionally(@kng_kasus)
51
57
  end
52
58
 
53
59
  end
@@ -170,9 +176,11 @@ protected
170
176
  return x.kng_kasus
171
177
  end
172
178
  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
179
+ if x.kind_of? Numeric
180
+ c = meta_class.const_get :KASUS
181
+ if i > 0 and i <= c.size
182
+ return c[i-1].to_sym
183
+ end
176
184
  end
177
185
  return abbrev_kasus[x]
178
186
  end
@@ -214,4 +222,4 @@ protected
214
222
 
215
223
  end
216
224
 
217
- end
225
+ end
@@ -15,22 +15,83 @@
15
15
  # (c) 2011 by Hannes Georg
16
16
  #
17
17
 
18
+ require 'facets/numeric/round.rb'
19
+
18
20
  module Humanized
19
21
  module Number
20
22
 
21
- def number(humanizer, number, format = 'default')
22
- if format == 'default'
23
+ class PartitionEnumerator
24
+
25
+ include Enumerable
26
+
27
+ def initialize(range, size)
28
+ @range = range
29
+ @size = size
30
+ end
31
+ def each
32
+ i = @range.first
33
+ size = @range.last - @range.first
34
+ e = @range.end
35
+ if @range.exclude_end?
36
+ e = e - 1
37
+ else
38
+ size = size + 1
39
+ end
40
+ m = size.modulo(@size)
41
+ if m != 0
42
+ yield(i...(i+m))
43
+ i = i+m
44
+ end
45
+ while( i <= e )
46
+ yield(i...(i+@size))
47
+ i = i+@size
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+ def number(humanizer, number, format = 'default', precision='')
54
+
55
+ if format == 'default' or format.nil?
23
56
  it = number._(:format,:default)
24
57
  else
58
+ format = format.to_sym
25
59
  it = number._.format( format._ | :default._ )
26
60
  end
27
- f = humanizer.get(it)
28
- if f.kind_of? String
29
- return sprintf(f,number)
61
+
62
+ if precision.kind_of? String and precision.length > 0
63
+ precision = x_to_i(precision)
64
+ end
65
+
66
+ unless precision.kind_of? Integer
67
+ precision = humanizer.get( it.precision , :default=>0 )
68
+ end
69
+
70
+ num = number.round_at(precision).to_s
71
+ full, frac = num.split('.', 2)
72
+
73
+ if( full.length > 3 )
74
+ separator = humanizer.get( it.separator , :default=>'' )
75
+ if separator.length > 0
76
+ full = PartitionEnumerator.new(0...full.length, 3).map{|rng|
77
+ full[rng]
78
+ }.join(separator)
79
+ end
30
80
  end
31
- warn "Unable to find Number format: #{it.inspect}."
32
- return ''
81
+
82
+ if( precision > 0 )
83
+ delimiter = humanizer.get( it.delimiter , :default=>'.' )
84
+ if frac.length > precision
85
+ frac = frac[0...precision]
86
+ else
87
+ frac = frac.ljust(precision, '0')
88
+ end
89
+ return [full, frac].join(delimiter)
90
+ end
91
+
92
+ return full
93
+
33
94
  end
34
95
 
35
96
  end
36
- end
97
+ end
@@ -15,28 +15,30 @@
15
15
  # (c) 2011 by Hannes Georg
16
16
  #
17
17
 
18
+ require 'facets/hash/graph.rb'
19
+
18
20
  module Humanized
19
- # A {Scope} is _the_ way to tell a {Humanizer} what you want from it.
21
+ # A {Query} is _the_ way to tell a {Humanizer} what you want from it.
20
22
  # It contains of three parts:
21
23
  # * {#path a list of paths}, which will be looked up in a {Source source}
22
24
  # * {#default a default}, which will be used if nothing was found
23
25
  # * {#variables variables}, which will be used to interpolate a found string
24
26
  # That's all you need!
25
- # The good thing: you'll unlikly create a scope by hand, that's done automatically with "_"!
27
+ # The good thing: you'll unlikly create a query by hand, that's done automatically with "_"!
26
28
  #
27
29
  # == Examples
28
30
  #
29
31
  # The basic steps:
30
- # # Creates a scope which looks up ":a" with no default and no variables:
32
+ # # Creates a query which looks up ":a" with no default and no variables:
31
33
  # :a._
32
- # # Creates a scope which looks up nothing, has a default of "String" but no variables:
34
+ # # Creates a query which looks up nothing, has a default of "String" but no variables:
33
35
  # "String"._
34
- # # Creates a scope which looks up nothing, has no default but the variable :foo = "bar"
36
+ # # Creates a query which looks up nothing, has no default but the variable :foo = "bar"
35
37
  # {:foo => 'bar'}._
36
38
  #
37
39
  # Combining these steps brings the power:
38
40
  #
39
- # # Creates a scope which looks up ":a", has a default of "String" and the variable :foo = "bar"
41
+ # # Creates a query which looks up ":a", has a default of "String" and the variable :foo = "bar"
40
42
  # :a._ + "String"._ + {:foo => 'bar'}._
41
43
  # # Shorthand for this:
42
44
  # :a._("String", :foo => 'bar')
@@ -49,7 +51,7 @@ module Humanized
49
51
  # class Admin < User
50
52
  # end
51
53
  # end
52
- # # Creates a scope matching ":site, :admin" or ":site, :user":
54
+ # # Creates a query matching ":site, :admin" or ":site, :user":
53
55
  # Site::Admin._
54
56
  # # This creates the same:
55
57
  # Site::Admin.new._
@@ -58,32 +60,32 @@ module Humanized
58
60
  # # This matches ":a, :b, :c":
59
61
  # [:a, :b, :c]._
60
62
  #
61
- # Finally for Scopes itself:
62
- # # Given scope is a Scope this is always true:
63
- # scope._._ == scope._
63
+ # Finally for Querys itself:
64
+ # # Given query is a Query this is always true:
65
+ # query._._ == query._
64
66
  #
65
67
  # I could continue the whole day ...
66
68
  #
67
69
  # == Tricks
68
- # A Scope responds to any method giving a new Scope suffixed by the method name
70
+ # A Query responds to any method giving a new Query suffixed by the method name
69
71
  # # Looks up ":a, :b, :c"
70
72
  # :a._.b.c
71
- # "_" can also take a block which is instance evaled on the scope:
73
+ # "_" can also take a block which is instance evaled on the query:
72
74
  # # Looks up ":a, :b, :c"
73
75
  # :a._{ b.c }
74
76
  # # Looks up ":a, :x" or ":a, :y"
75
77
  # :a._{ x | y }
76
- # There are two special scopes:
78
+ # There are two special querys:
77
79
  # # Looks up "", which will we be the whole source
78
- # Humanized::Scope::Root
80
+ # Humanized::Query::Root
79
81
  # # Looks up nothing
80
- # Humanized::Scope::None
82
+ # Humanized::Query::None
81
83
  #
82
- class Scope
84
+ class Query
83
85
 
84
86
  include Enumerable
85
87
  # @private
86
- UNMAGIC_METHODS = [:to_ary]
88
+ UNMAGIC_METHODS = [:to_ary, :to_s, :to_sym, :freeze]
87
89
  # @private
88
90
  NAME_REGEX = /[a-z_]+/.freeze
89
91
  # @private
@@ -92,25 +94,28 @@ module Humanized
92
94
  attr_reader :path, :depth, :variables, :default
93
95
 
94
96
  def self.from_str(str)
95
- Scope.new([ str.explode('.').map(&:to_sym) ])
97
+ Query.new([ str.explode('.').map(&:to_sym) ])
96
98
  end
97
99
 
98
- def initialize(path = [[]], depth = 1, variables = {}, default = nil)
100
+ def initialize(path = [[]], depth = nil, variables = {}, default = nil)
99
101
  @path = path.uniq
100
- @path.each do |path|
101
- path.freeze
102
+ @path.each do |p|
103
+ p.freeze
102
104
  end
103
105
  @path.freeze
104
- @depth = depth
105
- @variables = variables
106
+ if !depth.nil? and path.size != @path.size
107
+ depth -= ( path.size - @path.size )
108
+ end
109
+ @depth = (depth || @path.size)
110
+ @variables = variables.graph do |k,v| [k.to_sym, v] end
106
111
  @default = default
107
112
  end
108
113
 
109
114
  # This method is a here to enable awesome DSL.
110
115
  #== Example
111
- # s = Scope.new
112
- # s.defining.a.scope.using_methods # gives: (defining.a.scope.using_methods)
113
- # s.defining(:a,:scope,:using_methods) # gives: (defining.a.scope.using_methods)
116
+ # s = Query.new
117
+ # s.defining.a.query.using_methods # gives: (defining.a.query.using_methods)
118
+ # s.defining(:a,:query,:using_methods) # gives: (defining.a.query.using_methods)
114
119
  # s.this{ is.awesome | is.awful } # gives: (this.is.awesome , this.is.awful)
115
120
  #
116
121
  def method_missing(name, *args, &block)
@@ -126,17 +131,21 @@ module Humanized
126
131
  end
127
132
 
128
133
  def ==(other)
129
- return false unless other.kind_of? Scope
130
- return @path == other.path
134
+ return false unless other.kind_of? Query
135
+ if @path == other.path and @variables == other.variables and @default == other.default and @depth == other.depth
136
+ return true
137
+ else
138
+ return false
139
+ end
131
140
  end
132
141
 
133
- # Creates a {Scope scope} which matches either self or the other scope.
142
+ # Creates a {Query query} which matches either self or the other query.
134
143
  # @example
135
144
  # # this will match ":to_be" and ":not_to_be":
136
145
  # ( :to_be._ | :not_to_be._ )
137
146
  #
138
- # @param [Scope] other another scope
139
- # @return [Scope] a new scope
147
+ # @param [Query] other another query
148
+ # @return [Query] a new query
140
149
  def |(other)
141
150
  return other if @path.none?
142
151
  return self.dup if other.none?
@@ -153,19 +162,38 @@ module Humanized
153
162
  i = i + sd
154
163
  j = j + od
155
164
  end
156
- return Scope.new( result, sd + od , self.variables.merge(other.variables), other.default)
165
+ return Query.new( result, sd + od , self.variables.merge(other.variables), other.default)
157
166
  end
158
167
 
159
- # Creates a new scope which will optionally match this scope suffixed with the key.
168
+ # Creates a new query which will optionally match this query suffixed with the key.
169
+ #
170
+ # @example
171
+ # # this will match ":borat_is_stupid, :not" and ":borat_is_stupid":
172
+ # :borat_is_stupid._.optionally(:not)
160
173
  #
161
174
  # @example
162
175
  # # this will match ":borat_is_stupid, :not" and ":borat_is_stupid":
163
176
  # :borat_is_stupid._.optionally(:not)
164
177
  #
165
178
  # @param key
166
- # @return [Scope] a new scope
167
- def optionally(key)
168
- return self._(key) | self
179
+ # @return [Query] a new query
180
+ def optionally(*keys)
181
+
182
+ return self if keys.none?
183
+
184
+ q = self._(*keys)
185
+
186
+ begin
187
+
188
+ keys.pop
189
+
190
+ q |= q._(*keys)
191
+
192
+ end while keys.any?
193
+
194
+ q |= self
195
+
196
+ return q
169
197
  end
170
198
 
171
199
  def [](*args)
@@ -179,21 +207,21 @@ module Humanized
179
207
  result << path + [arg]
180
208
  end
181
209
  end
182
- return Scope.new( result, args.size )
210
+ return Query.new( result, args.size )
183
211
  end
184
212
 
185
- # Chain scopes together
213
+ # Chain querys together
186
214
  # @example
187
215
  # # this will match ":a,:b,:c"
188
216
  # :a._ + :b._ + :c._
189
217
  #
190
- # @param *args an array of scopes for chaining
191
- # @return [Scope]
218
+ # @param *args an array of querys for chaining
219
+ # @return [Query]
192
220
  def +(*args)
193
221
  return self if args.none?
194
- if( args.first.kind_of? Scope )
222
+ if( args.first.kind_of? Query )
195
223
  s = args.first
196
- return Scope.new(@path, @depth, variables.merge(s.variables), self.default || s.default ) if @path.none? or s.path.none?
224
+ return Query.new(@path, @depth, variables.merge(s.variables), self.default || s.default ) if @path.none? or s.path.none?
197
225
  # TODO: maybe modify depth too?
198
226
  new_path = []
199
227
  @path.each do |x|
@@ -201,12 +229,12 @@ module Humanized
201
229
  new_path << x + path
202
230
  end
203
231
  end
204
- return Scope.new(new_path, s.depth, variables.merge(s.variables), self.default || s.default )
232
+ return Query.new(new_path, s.depth, variables.merge(s.variables), self.default || s.default )
205
233
  end
206
234
  if @path.none?
207
235
  return self
208
236
  end
209
- return Scope.new( @path.map{|x| x + args} , @depth , @variables, @default)
237
+ return Query.new( @path.map{|x| x + args} , @depth , @variables, @default)
210
238
  end
211
239
 
212
240
  def _(*args,&block)
@@ -215,9 +243,9 @@ module Humanized
215
243
  loop do
216
244
  break if args.none?
217
245
  arg = args.shift
218
- if arg.kind_of? Symbol or arg.kind_of? Scope
246
+ if arg.kind_of? Symbol or arg.kind_of? Query
219
247
  thiz += arg
220
- elsif arg.class == Hash
248
+ elsif arg.respond_to? :humanized_variables? and arg.humanized_variables?
221
249
  vars = arg
222
250
  else
223
251
  thiz += arg._
@@ -234,11 +262,11 @@ module Humanized
234
262
  end
235
263
 
236
264
  def with_variables(vars)
237
- Scope.new(@path, @depth, variables.merge(vars), @default)
265
+ Query.new(@path, @depth, variables.merge(vars), @default)
238
266
  end
239
267
 
240
268
  def with_default(default)
241
- Scope.new(@path, @depth, @variables, default)
269
+ Query.new(@path, @depth, @variables, default)
242
270
  end
243
271
 
244
272
  def inspect
@@ -261,4 +289,4 @@ module Humanized
261
289
 
262
290
 
263
291
  end
264
- end
292
+ end