class Vcard::V3_0::Grammar
Attributes
errors[RW]
strict[RW]
Public Class Methods
new(strict)
click to toggle source
# File lib/vobject/vcard/v3_0/grammar.rb, line 145 def initialize(strict) self.strict = strict self.errors = [] end
unfold(str)
click to toggle source
# File lib/vobject/vcard/v3_0/grammar.rb, line 17 def unfold(str) str.gsub(/[\n\r]+[ \t]/, "") end
Public Instance Methods
parse(vobject)
click to toggle source
# File lib/vobject/vcard/v3_0/grammar.rb, line 150 def parse(vobject) @ctx = Rsec::ParseContext.new self.class.unfold(vobject), "source" ret = vobject_grammar._parse @ctx if !ret || Rsec::INVALID[ret] if strict raise @ctx.generate_error "source" else errors << @ctx.generate_error("source") ret = { VCARD: nil, errors: errors.flatten } end end Rsec::Fail.reset ret end
vobject_grammar()
click to toggle source
# File lib/vobject/vcard/v3_0/grammar.rb, line 22 def vobject_grammar # properties with value cardinality 1 @cardinality1 = {} @cardinality1[:PARAM] = Set.new [:VALUE] @cardinality1[:PROP] = Set.new [:KIND, :N, :BDAY, :ANNIVERSARY, :GENDER, :PRODID, :REV, :UID] group = C::IANATOKEN linegroup = group << "." beginend = /BEGIN/i.r | /END/i.r # parameters && parameter types paramname = /ENCODING/i.r | /LANGUAGE/i.r | /CONTEXT/i.r | /TYPE/i.r | /VALUE/i.r | /PREF/i.r otherparamname = C::NAME_VCARD ^ paramname paramvalue = C::QUOTEDSTRING_VCARD.map { |s| s } | C::PTEXT_VCARD.map { |x, _| x.upcase } # prefvalue = /[0-9]{1,2}/i.r | "100".r valuetype = /URI/i.r | /DATE/i.r | /DATE-TIME/i.r | /BINARY/i.r | /PTEXT/i.r # mediaattr = /[!\"#$%&'*+.^A-Z0-9a-z_`i{}|~-]+/.r # mediavalue1 = mediaattr | C::QUOTEDSTRING_VCARD # mediatail = seq(";".r >> mediaattr, "=".r << mediavalue1).map do |(a, v)| # ";#{a}=#{v}" # end # rfc4288regname = /[A-Za-z0-9!#$&.+^+-]{1,127}/.r # rfc4288typename = rfc4288regname # rfc4288subtypename = rfc4288regname # mediavalue = seq(rfc4288typename << "/".r, rfc4288subtypename, # mediatail.star).map do |(t, s, tail)| # ret = "#{t}/#{s}" # ret = ret . tail[0] unless tail.empty? # ret # end pvalue_list = (seq(paramvalue << ",".r, lazy { pvalue_list }) & /[;:]/.r).map do |(e, list)| [e.sub(Regexp.new("^\"(.+)\"$"), '\1').gsub(/\\n/, "\n"), list].flatten end | (paramvalue & /[;:]/.r).map do |e| [e.sub(Regexp.new("^\"(.+)\"$"), '\1').gsub(/\\n/, "\n")] end typevaluelist = seq(C::IANATOKEN, ",".r >> lazy { typevaluelist }).map do |(t, l)| [t.upcase, l].flatten end | C::IANATOKEN.map { |t| [t.upcase] } quoted_string_list = (seq(C::QUOTEDSTRING_VCARD << ",".r, lazy { quoted_string_list }) & /[;:]/.r).map do |(e, list)| [e.sub(Regexp.new("^\"(.+)\"$"), '\1').gsub(/\\n/, "\n"), list].flatten end | (C::QUOTEDSTRING_VCARD & /[;:]/.r).map do |e| [e.sub(Regexp.new("^\"(.+)\"$"), '\1').gsub(/\\n/, "\n")] end # fmttypevalue = seq(rfc4288typename, "/", rfc4288subtypename).map {|x, _| x.join } rfc1766primarytag = /[A-Za-z]{1,8}/.r rfc1766subtag = seq("-", /[A-Za-z]{1,8}/.r) { |(a, b)| a + b } rfc1766language = seq(rfc1766primarytag, rfc1766subtag.star) do |(a, b)| a += b[0] unless b.empty? a end param = seq(/ENCODING/i.r, "=", /b/.r) do |(name, _, val)| { name.upcase.tr("-", "_").to_sym => val } end | seq(/LANGUAGE/i.r, "=", rfc1766language) do |(name, _, val)| { name.upcase.tr("-", "_").to_sym => val.upcase } end | seq(/CONTEXT/i.r, "=", /word/.r) do |(name, _, val)| { name.upcase.tr("-", "_").to_sym => val.upcase } end | seq(/TYPE/i.r, "=", typevaluelist) do |(name, _, val)| { name.upcase.tr("-", "_").to_sym => val } end | seq(/VALUE/i.r, "=", valuetype) do |(name, _, val)| { name.upcase.tr("-", "_").to_sym => val } end | /PREF/i.r.map do |_name| # this is likely erroneous use of VCARD 2.1 convention in RFC2739; converting to canonical TYPE=PREF { TYPE: ["PREF"] } end | seq(otherparamname, "=", pvalue_list) do |(name, _, val)| val = val[0] if val.length == 1 { name.upcase.tr("-", "_").to_sym => val } end | seq(paramname, "=", pvalue_list) do |(name, _, val)| parse_err("Violated format of parameter value #{name} = #{val}") end params = seq(";".r >> param & ";", lazy { params }) do |(p, ps)| p.merge(ps) do |key, old, new| if @cardinality1[:PARAM].include?(key) parse_err("Violated cardinality of parameter #{key}") end [old, new].flatten # deal with duplicate properties end end | seq(";".r >> param).map { |e| e[0] } contentline = seq(linegroup._?, C::NAME_VCARD, params._? << ":".r, C::VALUE, /(\r|\n|\r\n)/) do |(g, name, p, value, _)| key = name.upcase.tr("-", "_").to_sym hash = { key => {} } hash[key][:value], errors1 = Typegrammars.typematch(strict, key, p[0], :GENERIC, value, @ctx) errors << errors1 hash[key][:group] = g[0] unless g.empty? errors << Paramcheck.paramcheck(strict, key, p.empty? ? {} : p[0], @ctx) hash[key][:params] = p[0] unless p.empty? hash end props = seq(contentline, lazy { props }) do |(c, rest)| c.merge(rest) do |key, old, new| if @cardinality1[:PROP].include?(key.upcase) parse_err("Violated cardinality of property #{key}") end [old, new].flatten # deal with duplicate properties end end | ("".r & beginend).map { {} } calpropname = /VERSION/i.r calprop = seq(linegroup._?, calpropname << ":".r, C::VALUE, /[\r\n]/) do |(g, key, value, _)| key = key.upcase.tr("-", "_").to_sym hash = { key => {} } hash[key][:value], errors1 = Typegrammars.typematch(strict, key, nil, :VCARD, value, @ctx) errors << errors1 hash[key][:group] = g[0] unless g.empty? hash end vobject = seq(linegroup._?, /BEGIN:VCARD[\r\n]/i.r >> calprop, props, linegroup._? << /END:VCARD[\r\n]/i.r) do |(_g, v, rest, _g1)| # TODO what do we do with the groups here? parse_err("Missing VERSION attribute") unless v.has_key?(:VERSION) parse_err("Missing FN attribute") unless rest.has_key?(:FN) parse_err("Missing N attribute") unless rest.has_key?(:N) rest.delete(:END) { VCARD: v.merge(rest), errors: errors.flatten } end vobject.eof end
Private Instance Methods
parse_err(msg)
click to toggle source
# File lib/vobject/vcard/v3_0/grammar.rb, line 167 def parse_err(msg) if strict raise @ctx.report_error msg, "source" else errors << @ctx.report_error(msg, "source") end end