Module: Virginity::Query
- Included in:
- DirectoryInformation
- Defined in:
- lib/virginity/dir_info/query.rb
Overview
Helper methods to perform queries on lines in a DirectoryInformation instance
query format: [group.][name][:value]
examples:
-
“FN” searches for FN-fields
-
“FN:John Smith” searches for an FN-field with the value “John Smith”
-
“:John Smith” searches for any field with the value “John Smith”
-
“item1.:John Smith” searches for any field with the value “John Smith” and group item1
Defined Under Namespace
Classes: InvalidQuery
Constant Summary collapse
- GROUP =
/#{Bnf::NAME}\./
- NAME =
/#{Bnf::NAME}/
- SEMICOLON =
/\;/
- COLON =
/\:/
- COMMA =
/,/
- EQUALS =
/=/
- KEY =
/#{Bnf::NAME}/
- PARAM_NAME =
/((X|x)\-)?(\w|\-)+/
- PARAM_VALUE =
/#{Bnf::PVALUE}/
Class Method Summary collapse
Instance Method Summary collapse
- #find_first(query = {}) ⇒ Object
-
#first_match(query = "") ⇒ Object
return the first match for query q.
- #line_matches_query?(line, q, v) ⇒ Boolean
- #lines_with_name(name = "") ⇒ Object
- #query(query = "") ⇒ Object (also: #/)
- #where(query = {}) ⇒ Object
Class Method Details
.decode_query(query) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/virginity/dir_info/query.rb', line 22 def self.decode_query(query) scanner = StringScanner.new(query) # does the query start with a name that ends in a dot? if group = scanner.scan(GROUP) group.chomp!(".") end name = scanner.scan(NAME) # could be nil params = params(scanner) value = nil if scanner.skip(COLON) value = scanner.rest end [group, name, params, value] end |
.params(scanner) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/virginity/dir_info/query.rb', line 42 def self.params(scanner) return nil unless scanner.skip(SEMICOLON) params = [] until scanner.check(COLON) or scanner.eos? # <--- check of end of string! and *check* for colon key = scanner.scan(PARAM_NAME) raise InvalidQuery unless scanner.skip(EQUALS) begin if value = scanner.scan(PARAM_VALUE) params << Param.new(key, Param::decode_value(value)) end break if scanner.skip(SEMICOLON) # after a semicolon, we expect key=(value)+ end until scanner.skip(COMMA).nil? # a comma indicates another value (TYPE=HOME,WORK) end params end |
Instance Method Details
#find_first(query = {}) ⇒ Object
136 137 138 139 140 |
# File 'lib/virginity/dir_info/query.rb', line 136 def find_first(query = {}) lines.detect do |line| query.all? { |q,v| line_matches_query?(line, q, v) } end end |
#first_match(query = "") ⇒ Object
return the first match for query q. By definition this is equivalent to query(q).first but it is faster.
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/virginity/dir_info/query.rb', line 70 def first_match(query = "") group, name, params, value = Query::decode_query(query) lines.detect do |line| # to_s is used here to match a nil-group to the empty-group-query: "." (group.nil? || group == line.group.to_s) && (params.nil? || params.all? { |p| line.params.include?(p) }) && (name.nil? || line.has_name?(name)) && (value.nil? || value == line.raw_value) end end |
#line_matches_query?(line, q, v) ⇒ Boolean
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/virginity/dir_info/query.rb', line 87 def line_matches_query?(line, q, v) raise ArgumentError, "query cannot be nil { #{q.inspect} => #{v.inspect} }?" if v.nil? case q when :name line.has_name?(v) when :raw_value v == line.raw_value when :text return false unless line.respond_to? :text v == line.text when :sha1 return false unless line.respond_to? :sha1 v == line.sha1 when :group v == line.group when :values raise ArgumentError, "expected an array of values { #{q.inspect} => #{v.inspect} }?" unless v.is_a? Array if line.respond_to? :values if line.respond_to? :components # stuctured text, values are ordered and the lenght of the array is guaranteed to be correct. line.values == v else (line.values - v).empty? end else false end when :has_param # true if one param matches the array we feed it line.params.include? Param.new(v.first, v.last) when :has_param_with_key # true if one param matches the array we feed it line.params.any? { |p| p.has_key?(v) } when :has_type # true if one param matches the array we feed it line.params.include? Param.new('TYPE', v) when :params # all params match v, and no param is not matching raise NotImplementedError else raise ArgumentError, "what do you expect me to do with { #{q.inspect} => #{v.inspect} }?" end end |
#lines_with_name(name = "") ⇒ Object
81 82 83 84 85 |
# File 'lib/virginity/dir_info/query.rb', line 81 def lines_with_name(name = "") lines.select do |line| line.has_name?(name) end end |
#query(query = "") ⇒ Object Also known as: /
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/virginity/dir_info/query.rb', line 58 def query(query = "") group, name, params, value = Query::decode_query(query) lines.select do |line| # to_s is used here to match a nil-group to the empty-group-query: "." (group.nil? || group == line.group.to_s) && (params.nil? || params.all? { |p| line.params.include? p }) && (name.nil? || line.has_name?(name)) && (value.nil? || value == line.raw_value) end end |
#where(query = {}) ⇒ Object
130 131 132 133 134 |
# File 'lib/virginity/dir_info/query.rb', line 130 def where(query = {}) lines.select do |line| query.all? { |q,v| line_matches_query?(line, q, v) } end end |