Module: SDL4R

Defined in:
lib/sdl4r/sdl4r.rb,
lib/sdl4r/tag.rb,
lib/sdl4r/parser.rb,
lib/sdl4r/sdl_binary.rb,
lib/sdl4r/parser/token.rb,
lib/sdl4r/parser/reader.rb,
lib/sdl4r/sdl_time_span.rb,
lib/sdl4r/sdl_parse_error.rb,
lib/sdl4r/parser/tokenizer.rb,
lib/sdl4r/parser/time_span_with_zone.rb

Overview

– Simple Declarative Language (SDL) for Ruby Copyright 2005 Ikayzo, inc.

This program is free software. You can distribute or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation.

This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND, INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program; if not, contact the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++

Defined Under Namespace

Classes: Parser, SdlBinary, SdlParseError, SdlTimeSpan, Tag

Constant Summary collapse

MAX_INTEGER_32 =
2**31 - 1
MIN_INTEGER_32 =
-(2**31)
MAX_INTEGER_64 =
2**63 - 1
MIN_INTEGER_64 =
-(2**63)
BASE64_WRAP_LINE_LENGTH =
72

Class Method Summary collapse

Class Method Details

.coerce_or_fail(o) ⇒ Object

Coerce the type to a standard SDL type or raises an ArgumentError.

Returns o if of the following classes: NilClass, String, Numeric, Float, TrueClass, FalseClass, Date, DateTime, Time, SdlTimeSpan, SdlBinary,

Rationals are turned into Floats using Rational#to_f.

Raises:

  • (ArgumentError)


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/sdl4r/sdl4r.rb', line 151

def self.coerce_or_fail(o)
  case o

  when Rational
    return o.to_f

  when NilClass,
      String,
      Numeric,
      Float,
      TrueClass,
      FalseClass,
      Date,
      DateTime,
      Time,
      SdlTimeSpan,
      SdlBinary
    return o

  end

  raise ArgumentError, "#{o.class.name} is not coercible to an SDL type"
end

.format(o, add_quotes = true, line_prefix = "", indent = "\t") ⇒ Object

Creates an SDL string representation for a given object and returns it.

o

the object to format

add_quotes

indicates whether quotes will be added to Strings and characters (true by default)

line_prefix

the line prefix to use (“” by default)

indent

the indent string to use (“t” by default)



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
# File 'lib/sdl4r/sdl4r.rb', line 44

def self.format(o, add_quotes = true, line_prefix = "", indent = "\t")
  if o.is_a?(String)
    if add_quotes
      o_length = 0
      o.scan(/./m) { o_length += 1 } # counts the number of chars (as opposed of bytes)
      if o_length == 1
        return "'" + escape(o, "'") + "'"
      else
        return '"' + escape(o, '"') + '"'
      end
    else
      return escape(o)
    end
    
  elsif o.is_a?(Bignum)
    return o.to_s + "BD"
    
  elsif o.is_a?(Integer)
    if MIN_INTEGER_32 <= o and o <= MAX_INTEGER_32
      return o.to_s
    elsif MIN_INTEGER_64 <= o and o <= MAX_INTEGER_64
      return o.to_s + "L"
    else
      return o.to_s + "BD"
    end
    
  elsif o.is_a?(Float)
    return (o.to_s + "F")
    
  elsif o.is_a?(Rational)
    return o.to_f.to_s + "F"

  elsif o.is_a?(BigDecimal)
    s = o.to_s('F')
    s.sub!(/\.0$/, "")
    return "#{s}BD"

  elsif o.nil?
    return "null"

  elsif o.is_a?(SdlBinary)
    encoded_o = Base64.encode64(o.bytes)
    encoded_o.gsub!(/[\r\n]/m, "") # Remove the EOL inserted every 60 chars

    if add_quotes
      if encoded_o.length > BASE64_WRAP_LINE_LENGTH
        # FIXME: we should a constant or some parameter instead of hardcoded spaces
        wrap_lines_in_ascii(encoded_o, BASE64_WRAP_LINE_LENGTH, "#{line_prefix}#{indent}")
        encoded_o.insert(0, "[#{$/}")
        encoded_o << "#{$/}#{line_prefix}]"
      else
        encoded_o.insert(0, "[")
        encoded_o << "]"
      end
    end

    return encoded_o
    
  # Below, we use "#{o.year}" instead of "%Y" because "%Y" always emit 4 chars at least even if
  # the date is before 1000.
  elsif o.is_a?(DateTime) || o.is_a?(Time)
    milliseconds = get_datetime_milliseconds(o)

    if milliseconds == 0
      if o.zone
        return o.strftime("#{o.year}/%m/%d %H:%M:%S%Z")
      else
        return o.strftime("#{o.year}/%m/%d %H:%M:%S")
      end
    else
      if o.zone
        return o.strftime("#{o.year}/%m/%d %H:%M:%S." + milliseconds.to_s.ljust(3, '0') + "%Z")
      else
        return o.strftime("#{o.year}/%m/%d %H:%M:%S." + milliseconds.to_s.ljust(3, '0'))
      end
    end

  elsif o.is_a?(Date)
    return o.strftime("#{o.year}/%m/%d")
    
  else
    return o.to_s
  end
end

.new_date_time(year, month, day, hour, min, sec, time_zone_offset) ⇒ Object

Creates and returns the object representing a datetime (DateTime in the default implementation). This method is, by default, called by the Parser class. It could be overriden as follows in order to get Time instances from all the SDL4R parsers.

module SDL4R
  def self.new_date_time(year, month, day, hour, min, sec, time_zone_offset)
    Time.utc(year, month, day, hour, min, sec)
  end
end


139
140
141
# File 'lib/sdl4r/sdl4r.rb', line 139

def self.new_date_time(year, month, day, hour, min, sec, time_zone_offset)
  DateTime.civil(year, month, day, hour, min, sec, time_zone_offset)
end

.read(input) ⇒ Object

Creates and returns a tag named “root” and add all the tags specified in the given input.

input

String, IO, Pathname or URI.

root = SDL4R::read(<<EOF
planets {
  earth area_km2=510900000
  mars
}
EOF
)

root = SDL4R::read(Pathname.new("my_dir/my_file.sdl"))

IO.open("my_dir/my_file.sdl", "r") { |io|
  root = SDL4R::read(io)
}

root = SDL4R::read(URI.new("http://my_site/my_file.sdl"))


232
233
234
# File 'lib/sdl4r/sdl4r.rb', line 232

def self.read(input)
  Tag.new("root").read(input)
end

.SdlBinary(o) ⇒ Object

Try to coerce ‘o’ into a SdlBinary. Raise an ArgumentError if it fails.



72
73
74
75
76
77
78
79
80
# File 'lib/sdl4r/sdl_binary.rb', line 72

def self.SdlBinary(o)
  if o.kind_of? SdlBinary
    return o
  elsif o.kind_of? String
    return SdlBinary.new(o)
  else
    raise ArgumentError, "can't coerce argument"
  end
end

.to_attribute_map(s) ⇒ Object

Parse a string representing the attributes portion of an SDL tag and return the results as a map.

Example

hash = SDL4R.to_attribute_hash("value=1 debugging=on time=12:24:01");

# { "value" => 1, "debugging" => true, "time" => SdlTimeSpan.new(12, 24, 01) }

Raises:

  • (ArgumentError)


270
271
272
273
# File 'lib/sdl4r/sdl4r.rb', line 270

def self.to_attribute_map(s)
  raise ArgumentError, "'s' cannot be null" if s.nil?
  return read("atts " + s).child.attributes
end

.to_value(s) ⇒ Object

Parses and returns the value corresponding with the specified SDL literal.

SDL4R.to_value("\"abcd\"") # => "abcd"
SDL4R.to_value("1") # => 1
SDL4R.to_value("null") # => nil

Raises:

  • (ArgumentError)


242
243
244
245
# File 'lib/sdl4r/sdl4r.rb', line 242

def self.to_value(s)
  raise ArgumentError, "'s' cannot be null" if s.nil?
  return read(s).child.value
end

.to_value_array(s) ⇒ Object

Example

array = SDL4R.to_value_array("1 true 12:24:01")

Will return an int, a boolean, and a time span.

Raises:

  • (ArgumentError)


256
257
258
259
# File 'lib/sdl4r/sdl4r.rb', line 256

def self.to_value_array(s)
  raise ArgumentError, "'s' cannot be null" if s.nil?
  return read(s).child.values
end

.validate_identifier(identifier) ⇒ Object

Validates an SDL identifier String. SDL Identifiers must start with a Unicode letter or underscore (_) and contain only unicode letters, digits, underscores (_), dashes(-) and periods (.).

Raises

ArgumentError if the identifier is not legal

TODO: support UTF-8 identifiers



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/sdl4r/sdl4r.rb', line 184

def self.validate_identifier(identifier)
  if identifier.nil? or identifier.empty?
    raise ArgumentError, "SDL identifiers cannot be null or empty."
  end

  # in Java, was if(!Character.isJavaIdentifierStart(identifier.charAt(0)))
  unless identifier =~ /^[a-zA-Z_]/
    raise ArgumentError,
      "'" + identifier[0..0] +
      "' is not a legal first character for an SDL identifier. " +
      "SDL Identifiers must start with a unicode letter or " +
      "an underscore (_)."
  end
  
  unless identifier.length == 1 or identifier =~ /^[a-zA-Z_][a-zA-Z_0-9\-\.]*$/
    for i in 1..identifier.length
      unless identifier[i..i] =~ /^[a-zA-Z_0-9\-]$/
        raise ArgumentError,
          "'" + identifier[i..i] + 
          "' is not a legal character for an SDL identifier. " +
          "SDL Identifiers must start with a unicode letter or " +
          "underscore (_) followed by 0 or more unicode " +
          "letters, digits, underscores (_), or dashes (-)"
      end
    end
  end
end