Class: Humanized::Query

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/humanized/query.rb

Overview

Humanized::Query::None

Constant Summary collapse

UNMAGIC_METHODS =
[:to_ary, :to_s, :to_sym, :freeze]
NAME_REGEX =
/[a-z_]+/.freeze
OPTIONAL_NAME_REGEX =
/([a-z_]+)\?/.freeze
IS_STRING =
lambda{|x| x.kind_of? String }
Root =
self.new([[]],1)
None =
self.new([],0)
Meta =
self.new([[:__meta__]],1)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = [[]], depth = nil, variables = {}, default = nil) ⇒ Query

Returns a new instance of Query.



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/humanized/query.rb', line 100

def initialize(path = [[]], depth = nil, variables = {}, default = nil)
  @path = path.uniq
  @path.each do |p|
    p.freeze
  end
  @path.freeze
  if !depth.nil? and path.size != @path.size
    depth -= ( path.size - @path.size )
  end
  @depth = (depth || @path.size)
  @variables = variables.graph do |k,v| [k.to_sym, v] end
  @default = default
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

This method is a here to enable awesome DSL.

Example

s = Query.new
s.defining.a.query.using_methods # gives: (defining.a.query.using_methods)
s.defining(:a,:query,:using_methods) # gives: (defining.a.query.using_methods)
s.this{ is.awesome | is.awful } # gives: (this.is.awesome , this.is.awful)


121
122
123
124
125
126
127
128
129
130
131
# File 'lib/humanized/query.rb', line 121

def method_missing(name, *args, &block)
  return super if UNMAGIC_METHODS.include? name
  name_str = name.to_s
  if OPTIONAL_NAME_REGEX =~ name_str
    return ( self + $1.to_sym | self )._(*args,&block)
  end
  if NAME_REGEX =~ name_str
    return ( self + name )._(*args,&block)
  end
  super
end

Instance Attribute Details

#defaultObject (readonly)

Returns the value of attribute default.



94
95
96
# File 'lib/humanized/query.rb', line 94

def default
  @default
end

#depthObject (readonly)

Returns the value of attribute depth.



94
95
96
# File 'lib/humanized/query.rb', line 94

def depth
  @depth
end

#pathObject (readonly)

Returns the value of attribute path.



94
95
96
# File 'lib/humanized/query.rb', line 94

def path
  @path
end

#variablesObject (readonly)

Returns the value of attribute variables.



94
95
96
# File 'lib/humanized/query.rb', line 94

def variables
  @variables
end

Class Method Details

.from_str(str) ⇒ Object



96
97
98
# File 'lib/humanized/query.rb', line 96

def self.from_str(str)
  Query.new([ str.explode('.').map(&:to_sym) ])
end

Instance Method Details

#+(*args) ⇒ Query

Chain querys together

Examples:

# this will match ":a,:b,:c"
:a._ + :b._ + :c._

Parameters:

  • *args

    an array of querys for chaining

Returns:



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/humanized/query.rb', line 220

def +(*args)
  return self if args.none?
  if( args.first.kind_of? Query )
    s = args.first
    return Query.new(@path, @depth, variables.merge(s.variables), self.default || s.default ) if @path.none? or s.path.none?
    # TODO: maybe modify depth too?
    new_path = []
    @path.each do |x|
      s.each do |path|
        new_path << x + path
      end
    end
    return Query.new(new_path, s.depth, variables.merge(s.variables), self.default || s.default )
  end
  if @path.none?
    return self
  end
  return Query.new( @path.map{|x| x + args} , @depth , @variables, @default)
end

#==(other) ⇒ Object



133
134
135
136
137
138
139
140
# File 'lib/humanized/query.rb', line 133

def ==(other)
  return false unless other.kind_of? Query
  if @path == other.path and @variables == other.variables and @default == other.default and @depth == other.depth
    return true
  else
    return false
  end
end

#[](*args) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/humanized/query.rb', line 199

def [](*args)
  sp = self.path
  sd = self.depth
  op = args
  od = 1
  result = []
  self.each do |path|
    args.each do |arg|
      result << path + [arg]
    end
  end
  return Query.new( result, args.size )
end

#_(*args, &block) ⇒ Object



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/humanized/query.rb', line 240

def _(*args,&block)
  thiz = self
  vars = nil
  loop do
    break if args.none?
    arg = args.shift
    if arg.kind_of? Symbol or arg.kind_of? Query
      thiz += arg
    elsif arg.respond_to? :humanized_variables? and arg.humanized_variables?
      vars = arg
    else
      thiz += arg._
    end
  end
  if block_given?
    thiz = thiz.instance_eval(&block)
  end
  if vars
    return thiz.with_variables(vars)
  else
    return thiz
  end
end

#each {|path| ... } ⇒ Object

Iterates over all possible paths.

Yield Parameters:



278
279
280
# File 'lib/humanized/query.rb', line 278

def each(&block)
  @path.each(&block)
end

#humanization_keyObject



282
283
284
# File 'lib/humanized/query.rb', line 282

def humanization_key
  return self
end

#inspectObject



272
273
274
# File 'lib/humanized/query.rb', line 272

def inspect
  return '(' + @path.map{|p| p.join '.'}.join(' , ') + ' '+depth.to_s+' v='+variables.inspect+' d='+default.inspect+')'
end

#optionally(*keys) ⇒ Query

Creates a new query which will optionally match this query suffixed with the key.

Examples:

# this will match ":borat_is_stupid, :not" and ":borat_is_stupid":
:borat_is_stupid._.optionally(:not)
# this will match ":borat_is_stupid, :not" and ":borat_is_stupid":
:borat_is_stupid._.optionally(:not)

Parameters:

  • key

Returns:

  • (Query)

    a new query



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/humanized/query.rb', line 180

def optionally(*keys)
  
  return self if keys.none?
  
  q = self._(*keys)
  
  begin
  
    keys.pop
    
    q |= q._(*keys)
  
  end until keys.empty?

  q |= self

  return q
end

#to_humanized(humanizer) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/humanized/query.rb', line 288

def to_humanized(humanizer)
  vars = self.variables
  if vars[:self].respond_to? :to_humanized
    return vars[:self].to_humanized(humanizer)
  end
  default = self.default
  result = humanizer.source.get(self, :default=>default, :accepts=>IS_STRING)
  result = default unless result.kind_of? String
  if result.kind_of? String
    return humanizer.interpolate(result,vars)
  else
    if humanizer.logger
      humanizer.logger.error do
        nnt = "\n\t\t"
        "Expected to retrieve a String, but got: #{result.inspect}\n\tQuery: #{path.inspect}\n\tBacktrace: \n\t\t#{Thread.current.backtrace[3..13].join(nnt)}"
      end
    end
    return ""
  end
end

#with_default(default) ⇒ Object



268
269
270
# File 'lib/humanized/query.rb', line 268

def with_default(default)
  Query.new(@path, @depth, @variables, default)
end

#with_variables(vars) ⇒ Object



264
265
266
# File 'lib/humanized/query.rb', line 264

def with_variables(vars)
  Query.new(@path, @depth, variables.merge(vars), @default)
end

#|(other) ⇒ Query

Creates a query which matches either self or the other query.

Examples:

# this will match ":to_be" and ":not_to_be":
( :to_be._ | :not_to_be._ )

Parameters:

  • other (Query)

    another query

Returns:

  • (Query)

    a new query



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/humanized/query.rb', line 149

def |(other)
  return other if @path.none?
  return self.dup if other.none?
  sp = self.path
  sd = self.depth
  op = other.path
  od = other.depth
  result = []
  i = 0
  j = 0
  while i < sp.size and j < op.size
    result.concat sp[i,sd] if sp.size > i
    result.concat op[j,od] if op.size > j
    i = i + sd
    j = j + od
  end
  return Query.new( result, sd + od , self.variables.merge(other.variables), other.default)
end