Class: Travis::Conditions::V1::Parser

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Boolean, Helper
Defined in:
lib/travis/conditions/v1/parser.rb

Constant Summary collapse

VAR =
/type|repo|head_repo|os|dist|group|sudo|language|sender|fork|
branch|head_branch|tag|commit_message/ix
PRED =
/present|blank|true|false/i
FUNC =
/env|concat/i
IN =
/in|not in/i
IS =
/is not|is/i
EQ =
/==|=/
NEQ =
/!=/
RE =
/=~|~=/
NRE =
/!~/
COMMA =
/,/
WORD =
/[^\s\(\)"',=!]+/
CONT =
/\\\s*[\n\r]/
OP =
{
  '='   => :eq,
  '=='  => :eq,
  '!='  => :not_eq,
  '=~'  => :match,
  '~='  => :match,
  '!~'  => :not_match
}
MSGS =
{
  invalid:     'Invalid condition: %p',
  parse_error: 'Could not parse %s',
  shell_var:   'Variable names cannot start with a dollar (shell code does not work). If you are trying to compare to an env var, please use env("name")',
  shell_str:   'Strings cannot start with a dollar (shell code does not work). This can be bypassed by quoting the string.'
}
BOUND =
/[\s,=)|]/

Constants included from Boolean

Boolean::AND, Boolean::BOP, Boolean::NOT, Boolean::OR

Constants included from Helper

Helper::CLOSE, Helper::OPEN, Helper::QUOTE, Helper::SPACE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Boolean

#expr, #expr_, #not_, #op, #oprd

Methods included from Helper

#err, #parens, #quoted, #space

Constructor Details

#initialize(str) ⇒ Parser

Returns a new instance of Parser.

Raises:



90
91
92
93
# File 'lib/travis/conditions/v1/parser.rb', line 90

def initialize(str)
  raise ArgumentError, MSGS[:invalid] % [str] unless str.is_a?(String)
  @str = StringScanner.new(filter(str))
end

Instance Attribute Details

#strObject (readonly)

Returns the value of attribute str.



88
89
90
# File 'lib/travis/conditions/v1/parser.rb', line 88

def str
  @str
end

Instance Method Details

#boundary?Boolean

Returns:



146
147
148
# File 'lib/travis/conditions/v1/parser.rb', line 146

def boundary?
  peek(1) =~ BOUND || str.eos?
end

#callObject



150
151
152
153
154
155
# File 'lib/travis/conditions/v1/parser.rb', line 150

def call
  return unless name = func
  args = parens { list }
  args or return
  return [:call, name.to_sym, args]
end

#commaObject



206
207
208
# File 'lib/travis/conditions/v1/parser.rb', line 206

def comma
  space { scan(COMMA) }
end

#eqObject



127
128
129
# File 'lib/travis/conditions/v1/parser.rb', line 127

def eq
  op = space { scan(EQ) || scan(NEQ) } and OP[op]
end

#error(key, *vals) ⇒ Object

Raises:



210
211
212
# File 'lib/travis/conditions/v1/parser.rb', line 210

def error(key, *vals)
  raise ParseError, MSGS[key] % vals
end

#filter(str) ⇒ Object



95
96
97
# File 'lib/travis/conditions/v1/parser.rb', line 95

def filter(str)
  str.gsub(CONT, ' ')
end

#funcObject



184
185
186
# File 'lib/travis/conditions/v1/parser.rb', line 184

def func
  space { scan(FUNC) }
end

#inObject



198
199
200
# File 'lib/travis/conditions/v1/parser.rb', line 198

def in
  space { scan(IN) }
end

#in_list(term) ⇒ Object



167
168
169
170
171
# File 'lib/travis/conditions/v1/parser.rb', line 167

def in_list(term)
  op = self.in or return
  list = parens { list! }
  [op.downcase.sub(' ', '_').to_sym, term, list]
end

#isObject



202
203
204
# File 'lib/travis/conditions/v1/parser.rb', line 202

def is
  space { scan(IS) }
end

#is_pred(term) ⇒ Object



161
162
163
164
165
# File 'lib/travis/conditions/v1/parser.rb', line 161

def is_pred(term)
  op = is or return
  pr = pred or return
  [op.downcase.sub(' ', '_').to_sym, term, pr.downcase.to_sym]
end

#listObject



177
178
179
180
181
182
# File 'lib/travis/conditions/v1/parser.rb', line 177

def list
  return [] unless item = var || call || val
  list = comma ? [item] + self.list : [item]
  skip(COMMA)
  list.compact
end

#list!Object



173
174
175
# File 'lib/travis/conditions/v1/parser.rb', line 173

def list!
  list.tap { |list| err 'a list of values' if list.empty? }
end

#operandObject



114
115
116
117
# File 'lib/travis/conditions/v1/parser.rb', line 114

def operand
  op = space { var || call || val }
  op or err('an operand')
end

#parseObject



99
100
101
102
103
# File 'lib/travis/conditions/v1/parser.rb', line 99

def parse
  res = expr
  error(:parse_error, string.inspect) unless res && !str.rest?
  res
end

#predObject



188
189
190
# File 'lib/travis/conditions/v1/parser.rb', line 188

def pred
  space { scan(PRED)&.to_sym }
end

#reObject



131
132
133
# File 'lib/travis/conditions/v1/parser.rb', line 131

def re
  op = space { scan(RE) || scan(NRE) } and OP[op]
end

#regexObject



119
120
121
122
123
124
125
# File 'lib/travis/conditions/v1/parser.rb', line 119

def regex
  val = call
  return [:reg, val] if val
  return unless reg = space { Regex.new(rest).scan }
  str.pos = str.pos + reg.size
  [:reg, reg.gsub(%r(^/|/$), '')] # or err('an operand')
end

#termObject



105
106
107
108
109
110
111
112
# File 'lib/travis/conditions/v1/parser.rb', line 105

def term
  lft = operand
  lst = in_list(lft) and return lst
  prd = is_pred(lft) and return prd
  op  = re and return [op, lft, regex]
  op  = eq and return [op, lft, operand]
  lft
end

#valObject



157
158
159
# File 'lib/travis/conditions/v1/parser.rb', line 157

def val
  val = quoted || word and [:val, val]
end

#varObject



135
136
137
138
139
140
141
142
# File 'lib/travis/conditions/v1/parser.rb', line 135

def var
  pos = str.pos
  var = scan(VAR)
  error(:shell_var) if var && var[0] == '$'
  return [:var, var.downcase.to_sym] if var && boundary?
  str.pos = pos
  nil
end

#wordObject



192
193
194
195
196
# File 'lib/travis/conditions/v1/parser.rb', line 192

def word
  str = space { scan(WORD) }
  error(:shell_str) if str && str[0] == '$'
  str
end