ruby-puppetdb 1.0.0.pre2
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/.gitignore +3 -0
- data/COPYING +202 -0
- data/Modulefile +7 -0
- data/README.md +233 -0
- data/Rakefile +24 -0
- data/bin/find-nodes +56 -0
- data/examples/nova_functions.pp +16 -0
- data/examples/query_node_examples.pp +12 -0
- data/examples/query_resource_examples.pp +48 -0
- data/lib/puppet/application/query.rb +22 -0
- data/lib/puppet/face/query.rb +60 -0
- data/lib/puppet/parser/functions/pdbfactquery.rb +31 -0
- data/lib/puppet/parser/functions/pdbnodequery.rb +38 -0
- data/lib/puppet/parser/functions/pdbnodequery_all.rb +40 -0
- data/lib/puppet/parser/functions/pdbquery.rb +41 -0
- data/lib/puppet/parser/functions/pdbresourcequery.rb +39 -0
- data/lib/puppet/parser/functions/pdbresourcequery_all.rb +37 -0
- data/lib/puppet/parser/functions/pdbstatusquery.rb +31 -0
- data/lib/puppet/parser/functions/query_facts.rb +27 -0
- data/lib/puppet/parser/functions/query_nodes.rb +27 -0
- data/lib/puppetdb.rb +2 -0
- data/lib/puppetdb/astnode.rb +86 -0
- data/lib/puppetdb/connection.rb +62 -0
- data/lib/puppetdb/grammar.y +57 -0
- data/lib/puppetdb/lexer.l +28 -0
- data/lib/puppetdb/lexer.rb +135 -0
- data/lib/puppetdb/parser.rb +368 -0
- data/lib/puppetdb/util.rb +18 -0
- data/ruby-puppetdb.gemspec +16 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/unit/puppet/parser/functions/pdbfactquery_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/pdbnodequery_all_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/pdbnodequery_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/pdbquery_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/pdbresourcequery_all_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/pdbresourcequery_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/pdbstatusquery_spec.rb +19 -0
- data/spec/unit/puppet/parser/functions/query_facts_spec.rb +11 -0
- data/spec/unit/puppet/parser/functions/query_nodes_spec.rb +11 -0
- metadata +118 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Puppet::Parser::Functions
|
2
|
+
newfunction(:pdbresourcequery_all, :type => :rvalue, :doc => "\
|
3
|
+
Perform a PuppetDB resource query
|
4
|
+
|
5
|
+
The first argument is the resource query.
|
6
|
+
Second argument is optional but allows you to specify the item you want
|
7
|
+
from the returned hash.
|
8
|
+
|
9
|
+
Returns an array of hashes or array of strings if second argument is provided.
|
10
|
+
|
11
|
+
Examples:
|
12
|
+
# Return an array of hashes describing all files that are owned by root.
|
13
|
+
$ret = pdbresourcequery_all(
|
14
|
+
['and',
|
15
|
+
['=','type','File'],
|
16
|
+
['=',['parameter','owner'],'root']])
|
17
|
+
|
18
|
+
# Return an array of host names having those resources
|
19
|
+
$ret = pdbresourcequery_all(
|
20
|
+
['and',
|
21
|
+
['=','type','File'],
|
22
|
+
['=',['parameter','owner'],'root']], 'certname')") do |args|
|
23
|
+
|
24
|
+
raise(Puppet::ParseError, "pdbresourcequery_all(): Wrong number of arguments " +
|
25
|
+
"given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
|
26
|
+
|
27
|
+
Puppet::Parser::Functions.autoloader.load(:pdbquery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbquery)
|
28
|
+
|
29
|
+
resq, info = args
|
30
|
+
ret = function_pdbquery(['resources', resq])
|
31
|
+
if info then
|
32
|
+
ret.collect {|x| x[info]}
|
33
|
+
else
|
34
|
+
ret
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Puppet::Parser::Functions
|
2
|
+
newfunction(:pdbstatusquery, :type => :rvalue, :doc => "\
|
3
|
+
Perform a PuppetDB node status query
|
4
|
+
|
5
|
+
The first argument is the node to get the status for.
|
6
|
+
Second argument is optional, if specified only return that specific bit of
|
7
|
+
status, one of 'name', 'deactivated', 'catalog_timestamp' and 'facts_timestamp'.
|
8
|
+
|
9
|
+
Returns an array of hashes or a array of strings if second argument is supplied.
|
10
|
+
|
11
|
+
Examples:
|
12
|
+
# Get status for foo.example.com
|
13
|
+
pdbstatusquery('foo.example.com')
|
14
|
+
# Get catalog_timestamp for foo.example.com
|
15
|
+
pdbstatusquery('foo.example.com', 'catalog_timestamp')") do |args|
|
16
|
+
|
17
|
+
raise(Puppet::ParseError, "pdbquery(): Wrong number of arguments " +
|
18
|
+
"given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
|
19
|
+
|
20
|
+
Puppet::Parser::Functions.autoloader.load(:pdbquery) unless Puppet::Parser::Functions.autoloader.loaded?(:pdbquery)
|
21
|
+
|
22
|
+
node, status = args
|
23
|
+
|
24
|
+
ret = function_pdbquery(["status/nodes/#{node}"])
|
25
|
+
if status then
|
26
|
+
ret[status]
|
27
|
+
else
|
28
|
+
ret
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Puppet::Parser::Functions.newfunction(:query_facts, :type => :rvalue, :arity => 2, :doc => <<-EOT
|
2
|
+
|
3
|
+
accepts two arguments, a query used to discover nodes, and a list of facts
|
4
|
+
that should be returned from those hosts.
|
5
|
+
|
6
|
+
The query specified should conform to the following format:
|
7
|
+
(Type[title] and fact_name<operator>fact_value) or ...
|
8
|
+
Package[mysql-server] and cluster_id=my_first_cluster
|
9
|
+
|
10
|
+
The facts list provided should be an array of fact names.
|
11
|
+
|
12
|
+
The result is a hash that maps the name of the nodes to a hash of facts that
|
13
|
+
contains the facts specified.
|
14
|
+
|
15
|
+
EOT
|
16
|
+
) do |args|
|
17
|
+
query, facts = args
|
18
|
+
|
19
|
+
require 'puppet/util/puppetdb'
|
20
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'puppetdb/connection'))
|
21
|
+
|
22
|
+
puppetdb = PuppetDB::Connection.new(Puppet::Util::Puppetdb.server, Puppet::Util::Puppetdb.port)
|
23
|
+
if query.is_a? String then
|
24
|
+
query = puppetdb.parse_query query
|
25
|
+
end
|
26
|
+
puppetdb.facts(facts, query)
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Puppet::Parser::Functions.newfunction(:query_nodes, :type => :rvalue, :arity => -2, :doc => <<-EOT
|
2
|
+
|
3
|
+
accepts two arguments, a query used to discover nodes, and a optional
|
4
|
+
fact that should be returned.
|
5
|
+
|
6
|
+
The query specified should conform to the following format:
|
7
|
+
(Type[title] and fact_name<operator>fact_value) or ...
|
8
|
+
Package["mysql-server"] and cluster_id=my_first_cluster
|
9
|
+
|
10
|
+
The second argument should be single fact (this argument is optional)
|
11
|
+
|
12
|
+
EOT
|
13
|
+
) do |args|
|
14
|
+
query, fact = args
|
15
|
+
|
16
|
+
require 'puppet/util/puppetdb'
|
17
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'puppetdb/connection'))
|
18
|
+
|
19
|
+
puppetdb = PuppetDB::Connection.new(Puppet::Util::Puppetdb.server, Puppet::Util::Puppetdb.port)
|
20
|
+
if fact then
|
21
|
+
query = puppetdb.parse_query query, :facts if query.is_a? String
|
22
|
+
puppetdb.facts([fact], query).each_value.to_a
|
23
|
+
else
|
24
|
+
query = puppetdb.parse_query query, :nodes if query.is_a? String
|
25
|
+
puppetdb.query(:nodes, query).collect { |n| n['name'] }
|
26
|
+
end
|
27
|
+
end
|
data/lib/puppetdb.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
class PuppetDB::ASTNode
|
2
|
+
attr_accessor :type, :value, :children
|
3
|
+
|
4
|
+
def initialize(type, value, children=[])
|
5
|
+
@type = type
|
6
|
+
@value = value
|
7
|
+
@children = children
|
8
|
+
end
|
9
|
+
|
10
|
+
# Generate the the query code for a subquery
|
11
|
+
#
|
12
|
+
# @param from_mode [Symbol] the mode you want to subquery from
|
13
|
+
# @param to_mode [Symbol] the mode you want to subquery to
|
14
|
+
# @param query the query inside the subquery
|
15
|
+
# @return [Array] the resulting subquery
|
16
|
+
def subquery(from_mode, to_mode, query)
|
17
|
+
return query if from_mode == to_mode
|
18
|
+
return ['in', (from_mode == :nodes) ? 'name' : 'certname',
|
19
|
+
['extract', (to_mode == :nodes) ? 'name' : 'certname',
|
20
|
+
["select-#{to_mode.to_s}", query]]]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Go through the AST and optimize boolean expressions into triplets etc
|
24
|
+
# Changes the AST in place
|
25
|
+
#
|
26
|
+
# @return The optimized AST
|
27
|
+
def optimize
|
28
|
+
case @type
|
29
|
+
when :booleanop
|
30
|
+
@children.each do |c|
|
31
|
+
if c.type == :booleanop and c.value == @value
|
32
|
+
c.children.each { |cc| @children << cc }
|
33
|
+
@children.delete c
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@children.each { |c| c.optimize }
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Evalutate the node and all children
|
42
|
+
#
|
43
|
+
# @param mode [Symbol] The query mode we are evaluating for
|
44
|
+
# @return [Array] the resulting PuppetDB query
|
45
|
+
def evaluate(mode = :nodes)
|
46
|
+
case @type
|
47
|
+
when :booleanop
|
48
|
+
return [@value.to_s, *evaluate_children(mode)]
|
49
|
+
when :subquery
|
50
|
+
return subquery(mode, @value, *evaluate_children(@value))
|
51
|
+
when :exp
|
52
|
+
case @value
|
53
|
+
when :equals then op = '='
|
54
|
+
when :greaterthan then op = '>'
|
55
|
+
when :lessthan then op = '<'
|
56
|
+
when :match then op = '~'
|
57
|
+
end
|
58
|
+
|
59
|
+
case mode
|
60
|
+
when :nodes # we are trying to query for facts but are in node mode, do a subquery
|
61
|
+
return subquery(mode, :facts, ['and', ['=', 'name', @children[0].evaluate(mode)], [op, 'value', @children[1].evaluate(mode)]])
|
62
|
+
when :facts
|
63
|
+
return ['and', ['=', 'name', @children[0].evaluate(mode)], [op, 'value', @children[1].evaluate(mode)]]
|
64
|
+
when :resources
|
65
|
+
return [op, ['parameter', @children[0].evaluate(mode)], @children[1].evaluate(mode)]
|
66
|
+
end
|
67
|
+
when :string
|
68
|
+
return @value.to_s
|
69
|
+
when :number
|
70
|
+
return @value
|
71
|
+
when :boolean
|
72
|
+
return @value
|
73
|
+
when :resourcetitle
|
74
|
+
return ['=', 'title', @value]
|
75
|
+
when :resourcetype
|
76
|
+
return ['=', 'type', @value]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Evaluate all children nodes
|
81
|
+
#
|
82
|
+
# @return [Array] The evaluate results of the children nodes
|
83
|
+
def evaluate_children(mode)
|
84
|
+
return children.collect { |c| c.evaluate mode }
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'puppetdb'
|
2
|
+
|
3
|
+
class PuppetDB::Connection
|
4
|
+
require 'rubygems'
|
5
|
+
require 'puppet'
|
6
|
+
require 'puppetdb/parser'
|
7
|
+
require 'puppet/network/http_pool'
|
8
|
+
require 'uri'
|
9
|
+
require 'json'
|
10
|
+
|
11
|
+
def initialize(host='puppetdb', port=443, use_ssl=true)
|
12
|
+
@host = host
|
13
|
+
@port = port
|
14
|
+
@use_ssl = use_ssl
|
15
|
+
@parser = PuppetDB::Parser.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parse a query string into a PuppetDB query
|
19
|
+
#
|
20
|
+
# @param query [String] the query string to parse
|
21
|
+
# @param endpoint [Symbol] the endpoint for which the query should be evaluated
|
22
|
+
# @return [Array] the PuppetDB query
|
23
|
+
def parse_query(query, endpoint=:nodes)
|
24
|
+
@parser.scan_str(query).optimize.evaluate endpoint
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get the listed facts for all nodes matching query
|
28
|
+
# return it as a hash of hashes
|
29
|
+
#
|
30
|
+
# @param facts [Array] the list of facts to fetch
|
31
|
+
# @param nodequery [Array] the query to find the nodes to fetch facts for
|
32
|
+
# @return [Hash] a hash of hashes with facts for each node mathing query
|
33
|
+
def facts(facts, nodequery, http=nil)
|
34
|
+
q = ['and', ['in', 'certname', ['extract', 'certname', ['select-facts', nodequery]]], ['or', *facts.collect { |f| ['=', 'name', f]}]]
|
35
|
+
facts = {}
|
36
|
+
query(:facts, q, http).each do |fact|
|
37
|
+
if facts.include? fact['certname'] then
|
38
|
+
facts[fact['certname']][fact['name']] = fact['value']
|
39
|
+
else
|
40
|
+
facts[fact['certname']] = {fact['name'] => fact['value']}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
facts
|
44
|
+
end
|
45
|
+
|
46
|
+
# Execute a PuppetDB query
|
47
|
+
#
|
48
|
+
# @param endpoint [Symbol] :resources, :facts or :nodes
|
49
|
+
# @param query [Array] query to execute
|
50
|
+
# @return [Array] the results of the query
|
51
|
+
def query(endpoint, query=nil, http=nil)
|
52
|
+
http ||= Puppet::Network::HttpPool.http_instance(@host, @port, @use_ssl)
|
53
|
+
headers = { "Accept" => "application/json" }
|
54
|
+
|
55
|
+
uri = "/v2/#{endpoint.to_s}"
|
56
|
+
uri += URI.escape "?query=#{query.to_json}" unless query.nil? or query.empty?
|
57
|
+
|
58
|
+
resp, data = http.get(uri, headers)
|
59
|
+
raise Puppet::Error, "PuppetDB query error: [#{resp.code}] #{resp.msg}, query: #{query.to_json}" unless resp.kind_of?(Net::HTTPSuccess)
|
60
|
+
return PSON.parse(data)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# vim: syntax=ruby
|
2
|
+
|
3
|
+
|
4
|
+
class PuppetDB::Parser
|
5
|
+
|
6
|
+
token LPAREN RPAREN LBRACK RBRACK LBRACE RBRACE
|
7
|
+
token EQUALS NOTEQUALS MATCH LESSTHAN GREATERTHAN
|
8
|
+
token NOT AND OR
|
9
|
+
token NUMBER STRING BOOLEAN
|
10
|
+
|
11
|
+
prechigh
|
12
|
+
right NOT
|
13
|
+
left EQUALS MATCH LESSTHAN GREATERTHAN
|
14
|
+
left AND
|
15
|
+
left OR
|
16
|
+
preclow
|
17
|
+
|
18
|
+
rule
|
19
|
+
query: exp
|
20
|
+
|
21
|
+
exp: LPAREN exp RPAREN { result = val[1] }
|
22
|
+
| NOT exp { result = ASTNode.new :booleanop, :not, [val[1]] }
|
23
|
+
| exp AND exp { result = ASTNode.new :booleanop, :and, [val[0], val[2]] }
|
24
|
+
| exp OR exp { result = ASTNode.new :booleanop, :or, [val[0], val[2]] }
|
25
|
+
| string EQUALS string { result = ASTNode.new :exp, :equals, [val[0], val[2]] }
|
26
|
+
| string EQUALS boolean { result = ASTNode.new :exp, :equals, [val[0], val[2]] }
|
27
|
+
| string EQUALS number { result = ASTNode.new :exp, :equals, [val[0], val[2]] }
|
28
|
+
| string GREATERTHAN number { result = ASTNode.new :exp, :greaterthan, [val[0], val[2]] }
|
29
|
+
| string LESSTHAN number { result = ASTNode.new :exp, :lessthan, [val[0], val[2]] }
|
30
|
+
| string MATCH string { result = ASTNode.new :exp, :match, [val[0], val[2]] }
|
31
|
+
| string NOTEQUALS number { result = ASTNode.new :booleanop, :not, [ASTNode.new(:exp, :equals, [val[0], val[2]])] }
|
32
|
+
| string NOTEQUALS boolean { result = ASTNode.new :booleanop, :not, [ASTNode.new(:exp, :equals, [val[0], val[2]])] }
|
33
|
+
| string NOTEQUALS string { result = ASTNode.new :booleanop, :not, [ASTNode.new(:exp, :equals, [val[0], val[2]])] }
|
34
|
+
| ressubquery
|
35
|
+
|
36
|
+
ressubquery: restype { result = ASTNode.new :subquery, :resources, [val[0]] }
|
37
|
+
| restitle { result = ASTNode.new :subquery, :resources, [val[0]] }
|
38
|
+
| resparams { result = ASTNode.new :subquery, :resources, [val[0]] }
|
39
|
+
| restype restitle { result = ASTNode.new :subquery, :resources, [ASTNode.new(:booleanop, :and, [val[0], val[1]])] }
|
40
|
+
| restitle resparams { result = ASTNode.new :subquery, :resources, [ASTNode.new(:booleanop, :and, [val[0], val[1]])] }
|
41
|
+
| restype resparams { result = ASTNode.new :subquery, :resources, [ASTNode.new(:booleanop, :and, [val[0], val[1]])] }
|
42
|
+
| restype restitle resparams { result = ASTNode.new :subquery, :resources, [ASTNode.new(:booleanop, :and, [val[0], val[1], val[2]])] }
|
43
|
+
|
44
|
+
restype: STRING { result = ASTNode.new :resourcetype, val[0] }
|
45
|
+
restitle: LBRACK STRING RBRACK { result = ASTNode.new :resourcetitle, val[1] }
|
46
|
+
resparams: LBRACE exp RBRACE { result = val[1] }
|
47
|
+
|
48
|
+
string: STRING { result = ASTNode.new :string, val[0] }
|
49
|
+
number: NUMBER { result = ASTNode.new :number, val[0] }
|
50
|
+
boolean: BOOLEAN { result = ASTNode.new :boolean, val[0] }
|
51
|
+
|
52
|
+
end
|
53
|
+
---- header ----
|
54
|
+
require 'puppetdb'
|
55
|
+
require 'puppetdb/lexer'
|
56
|
+
require 'puppetdb/astnode'
|
57
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# vim: syntax=ruby
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class PuppetDB::Lexer
|
6
|
+
rule
|
7
|
+
\s # whitespace no action
|
8
|
+
\( { [:LPAREN, text] }
|
9
|
+
\) { [:RPAREN, text] }
|
10
|
+
\[ { [:LBRACK, text] }
|
11
|
+
\] { [:RBRACK, text] }
|
12
|
+
\{ { [:LBRACE, text] }
|
13
|
+
\} { [:RBRACE, text] }
|
14
|
+
= { [:EQUALS, text] }
|
15
|
+
\!= { [:NOTEQUALS, text] }
|
16
|
+
~ { [:MATCH, text] }
|
17
|
+
< { [:LESSTHAN, text] }
|
18
|
+
> { [:GREATERTHAN, text] }
|
19
|
+
not { [:NOT, text] }
|
20
|
+
and { [:AND, text] }
|
21
|
+
or { [:OR, text] }
|
22
|
+
true { [:BOOLEAN, true]}
|
23
|
+
false { [:BOOLEAN, false]}
|
24
|
+
-?\d+ { [:NUMBER, text.to_i] }
|
25
|
+
-?\d+\.?(\d+)? { [:NUMBER, text.to_f] }
|
26
|
+
\"(\\.|[^\\"])*\" { [:STRING, JSON.load(text)] }
|
27
|
+
[\w_:]+ { [:STRING, text] }
|
28
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#--
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by rex 1.0.2
|
4
|
+
# from lexical definition file "puppetdb/lexer.l".
|
5
|
+
#++
|
6
|
+
|
7
|
+
require 'racc/parser'
|
8
|
+
# vim: syntax=ruby
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
module PuppetDB
|
13
|
+
class Lexer < Racc::Parser
|
14
|
+
require 'strscan'
|
15
|
+
|
16
|
+
class ScanError < StandardError ; end
|
17
|
+
|
18
|
+
attr_reader :lineno
|
19
|
+
attr_reader :filename
|
20
|
+
|
21
|
+
def scan_setup ; end
|
22
|
+
|
23
|
+
def action &block
|
24
|
+
yield
|
25
|
+
end
|
26
|
+
|
27
|
+
def scan_str( str )
|
28
|
+
scan_evaluate str
|
29
|
+
do_parse
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_file( filename )
|
33
|
+
@filename = filename
|
34
|
+
open(filename, "r") do |f|
|
35
|
+
scan_evaluate f.read
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def scan_file( filename )
|
40
|
+
load_file filename
|
41
|
+
do_parse
|
42
|
+
end
|
43
|
+
|
44
|
+
def next_token
|
45
|
+
@rex_tokens.shift
|
46
|
+
end
|
47
|
+
|
48
|
+
def scan_evaluate( str )
|
49
|
+
scan_setup
|
50
|
+
@rex_tokens = []
|
51
|
+
@lineno = 1
|
52
|
+
ss = StringScanner.new(str)
|
53
|
+
state = nil
|
54
|
+
until ss.eos?
|
55
|
+
text = ss.peek(1)
|
56
|
+
@lineno += 1 if text == "\n"
|
57
|
+
case state
|
58
|
+
when nil
|
59
|
+
case
|
60
|
+
when (text = ss.scan(/\s/))
|
61
|
+
;
|
62
|
+
|
63
|
+
when (text = ss.scan(/\(/))
|
64
|
+
@rex_tokens.push action { [:LPAREN, text] }
|
65
|
+
|
66
|
+
when (text = ss.scan(/\)/))
|
67
|
+
@rex_tokens.push action { [:RPAREN, text] }
|
68
|
+
|
69
|
+
when (text = ss.scan(/\[/))
|
70
|
+
@rex_tokens.push action { [:LBRACK, text] }
|
71
|
+
|
72
|
+
when (text = ss.scan(/\]/))
|
73
|
+
@rex_tokens.push action { [:RBRACK, text] }
|
74
|
+
|
75
|
+
when (text = ss.scan(/\{/))
|
76
|
+
@rex_tokens.push action { [:LBRACE, text] }
|
77
|
+
|
78
|
+
when (text = ss.scan(/\}/))
|
79
|
+
@rex_tokens.push action { [:RBRACE, text] }
|
80
|
+
|
81
|
+
when (text = ss.scan(/=/))
|
82
|
+
@rex_tokens.push action { [:EQUALS, text] }
|
83
|
+
|
84
|
+
when (text = ss.scan(/\!=/))
|
85
|
+
@rex_tokens.push action { [:NOTEQUALS, text] }
|
86
|
+
|
87
|
+
when (text = ss.scan(/~/))
|
88
|
+
@rex_tokens.push action { [:MATCH, text] }
|
89
|
+
|
90
|
+
when (text = ss.scan(/</))
|
91
|
+
@rex_tokens.push action { [:LESSTHAN, text] }
|
92
|
+
|
93
|
+
when (text = ss.scan(/>/))
|
94
|
+
@rex_tokens.push action { [:GREATERTHAN, text] }
|
95
|
+
|
96
|
+
when (text = ss.scan(/not/))
|
97
|
+
@rex_tokens.push action { [:NOT, text] }
|
98
|
+
|
99
|
+
when (text = ss.scan(/and/))
|
100
|
+
@rex_tokens.push action { [:AND, text] }
|
101
|
+
|
102
|
+
when (text = ss.scan(/or/))
|
103
|
+
@rex_tokens.push action { [:OR, text] }
|
104
|
+
|
105
|
+
when (text = ss.scan(/true/))
|
106
|
+
@rex_tokens.push action { [:BOOLEAN, true]}
|
107
|
+
|
108
|
+
when (text = ss.scan(/false/))
|
109
|
+
@rex_tokens.push action { [:BOOLEAN, false]}
|
110
|
+
|
111
|
+
when (text = ss.scan(/-?\d+/))
|
112
|
+
@rex_tokens.push action { [:NUMBER, text.to_i] }
|
113
|
+
|
114
|
+
when (text = ss.scan(/-?\d+\.?(\d+)?/))
|
115
|
+
@rex_tokens.push action { [:NUMBER, text.to_f] }
|
116
|
+
|
117
|
+
when (text = ss.scan(/\"(\\.|[^\\"])*\"/))
|
118
|
+
@rex_tokens.push action { [:STRING, JSON.load(text)] }
|
119
|
+
|
120
|
+
when (text = ss.scan(/[\w_:]+/))
|
121
|
+
@rex_tokens.push action { [:STRING, text] }
|
122
|
+
|
123
|
+
else
|
124
|
+
text = ss.string[ss.pos .. -1]
|
125
|
+
raise ScanError, "can not match: '" + text + "'"
|
126
|
+
end # if
|
127
|
+
|
128
|
+
else
|
129
|
+
raise ScanError, "undefined state: '" + state.to_s + "'"
|
130
|
+
end # case state
|
131
|
+
end # until ss
|
132
|
+
end # def scan_evaluate
|
133
|
+
|
134
|
+
end # class
|
135
|
+
end # module
|