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.
- data/lib/humanized.rb +23 -3
- data/lib/humanized/compiler.rb +36 -19
- data/lib/humanized/core_ext/array.rb +1 -1
- data/lib/humanized/core_ext/hash.rb +6 -2
- data/lib/humanized/core_ext/module.rb +2 -2
- data/lib/humanized/core_ext/nilclass.rb +1 -1
- data/lib/humanized/core_ext/object.rb +7 -1
- data/lib/humanized/core_ext/string.rb +1 -1
- data/lib/humanized/core_ext/symbol.rb +1 -1
- data/lib/humanized/humanizer.rb +188 -44
- data/lib/humanized/interpolater.rb +71 -0
- data/lib/humanized/interpolation/conjunctions.rb +6 -0
- data/lib/humanized/interpolation/date.rb +11 -3
- data/lib/humanized/{ref.rb → interpolation/default.rb} +9 -9
- data/lib/humanized/interpolation/german.rb +8 -6
- data/lib/humanized/interpolation/kng.rb +15 -7
- data/lib/humanized/interpolation/number.rb +69 -8
- data/lib/humanized/{scope.rb → query.rb} +77 -49
- data/lib/humanized/source.rb +37 -54
- data/lib/more/humanized/parser.rb +89 -0
- data/lib/more/humanized/parser/date.rb +0 -0
- data/lib/more/humanized/parser/numeric.rb +80 -0
- data/lib/more/humanized/parsing_humanizer.rb +73 -0
- metadata +59 -93
- data/lib/humanized/core_ext/date.rb +0 -21
- data/lib/humanized/core_ext/numeric.rb +0 -21
- data/lib/humanized/core_ext/time.rb +0 -21
| @@ -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 | 
            -
                 | 
| 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 | 
            -
             | 
| 21 | 
            -
               | 
| 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 | 
            -
                 | 
| 25 | 
            +
                ArticleQuery = Query::Meta.articles
         | 
| 24 26 |  | 
| 25 27 | 
             
                def a(humanizer, *args)
         | 
| 26 28 | 
             
                  Wrapper.wrap(args) do |t|
         | 
| 27 | 
            -
                    humanizer[ | 
| 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[ | 
| 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[ | 
| 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[ | 
| 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 | 
            -
                     | 
| 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 | 
            -
                 | 
| 174 | 
            -
             | 
| 175 | 
            -
                   | 
| 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 | 
            -
               | 
| 22 | 
            -
                 | 
| 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 | 
            -
                 | 
| 28 | 
            -
                if  | 
| 29 | 
            -
                   | 
| 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 | 
            -
                 | 
| 32 | 
            -
                 | 
| 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 { | 
| 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  | 
| 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  | 
| 32 | 
            +
            #  # Creates a query which looks up ":a" with no default and no variables:
         | 
| 31 33 | 
             
            #  :a._
         | 
| 32 | 
            -
            #  # Creates a  | 
| 34 | 
            +
            #  # Creates a query which looks up nothing, has a default of "String" but no variables:
         | 
| 33 35 | 
             
            #  "String"._
         | 
| 34 | 
            -
            #  # Creates a  | 
| 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  | 
| 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  | 
| 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  | 
| 62 | 
            -
            #  # Given  | 
| 63 | 
            -
            #   | 
| 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  | 
| 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  | 
| 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  | 
| 78 | 
            +
            # There are two special querys:
         | 
| 77 79 | 
             
            #  # Looks up "", which will we be the whole source
         | 
| 78 | 
            -
            #  Humanized:: | 
| 80 | 
            +
            #  Humanized::Query::Root
         | 
| 79 81 | 
             
            #  # Looks up nothing
         | 
| 80 | 
            -
            #  Humanized:: | 
| 82 | 
            +
            #  Humanized::Query::None
         | 
| 81 83 | 
             
            #
         | 
| 82 | 
            -
              class  | 
| 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 | 
            -
                   | 
| 97 | 
            +
                  Query.new([ str.explode('.').map(&:to_sym) ])
         | 
| 96 98 | 
             
                end
         | 
| 97 99 |  | 
| 98 | 
            -
                def initialize(path = [[]], depth =  | 
| 100 | 
            +
                def initialize(path = [[]], depth = nil, variables = {}, default = nil)
         | 
| 99 101 | 
             
                  @path = path.uniq
         | 
| 100 | 
            -
                  @path.each do | | 
| 101 | 
            -
                     | 
| 102 | 
            +
                  @path.each do |p|
         | 
| 103 | 
            +
                    p.freeze
         | 
| 102 104 | 
             
                  end
         | 
| 103 105 | 
             
                  @path.freeze
         | 
| 104 | 
            -
                   | 
| 105 | 
            -
             | 
| 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 =  | 
| 112 | 
            -
            #  s.defining.a. | 
| 113 | 
            -
            #  s.defining(:a,: | 
| 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?  | 
| 130 | 
            -
                   | 
| 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 { | 
| 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 [ | 
| 139 | 
            -
            # @return [ | 
| 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  | 
| 165 | 
            +
                  return Query.new( result, sd + od , self.variables.merge(other.variables), other.default)
         | 
| 157 166 | 
             
                end
         | 
| 158 167 |  | 
| 159 | 
            -
            # Creates a new  | 
| 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 [ | 
| 167 | 
            -
                def optionally( | 
| 168 | 
            -
                   | 
| 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  | 
| 210 | 
            +
                  return Query.new( result, args.size )
         | 
| 183 211 | 
             
                end
         | 
| 184 212 |  | 
| 185 | 
            -
            # Chain  | 
| 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  | 
| 191 | 
            -
            # @return [ | 
| 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?  | 
| 222 | 
            +
                  if( args.first.kind_of? Query )
         | 
| 195 223 | 
             
                    s = args.first
         | 
| 196 | 
            -
                    return  | 
| 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  | 
| 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  | 
| 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?  | 
| 246 | 
            +
                    if arg.kind_of? Symbol or arg.kind_of? Query
         | 
| 219 247 | 
             
                      thiz += arg
         | 
| 220 | 
            -
                    elsif arg. | 
| 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 | 
            -
                   | 
| 265 | 
            +
                  Query.new(@path, @depth, variables.merge(vars), @default)
         | 
| 238 266 | 
             
                end
         | 
| 239 267 |  | 
| 240 268 | 
             
                def with_default(default)
         | 
| 241 | 
            -
                   | 
| 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
         |