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 146 def initialize(strict) self.strict = strict self.errors = [] end
unfold(str)
click to toggle source
# File lib/vobject/vcard/v3_0/grammar.rb, line 18 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 151 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 23 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(&: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(&: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 168 def parse_err(msg) if strict raise @ctx.report_error msg, "source" else errors << @ctx.report_error(msg, "source") end end