Module: Doodle::DataTypes

Defined in:
lib/doodle/datatypes.rb

Defined Under Namespace

Classes: DataType

Constant Summary collapse

RX_ISODATE =
/^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)? ?Z$/

Instance Method Summary collapse

Instance Method Details

#boolean(name, params = { }, &block) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/doodle/datatypes.rb', line 73

def boolean(name, params = { }, &block)
  datatype name, params, block, { :default => true } do
    must "be true or false" do |v|
      [true, false].include?(v)
    end
    from NilClass do |v|
      false
    end
    from Integer do |v|
      v == 0 ? false : true
    end
    from String, Symbol do |v|
      case v.to_s
      when /^(yes|true|on|1)$/
        true
      when /^(no|false|off|0)$/
        false
      else
        v
      end
    end
  end
end

#datatype(name, params, block, type_params, &type_block) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/doodle/datatypes.rb', line 19

def datatype(name, params, block, type_params, &type_block)
  define name, params, block, { :using => DataType }.merge(type_params) do
    #p [:self, __doodle__.__inspect__]
    #p [:checking_values, values, values.class]
    if respond_to?(:values)
      if values.kind_of?(Range)
        must "be in range #{values}" do |s|
          values.include?(s)
        end
        # array of values
      elsif values.respond_to?(:size) && values.size > 0
        must "be one of #{values.join(', ')}" do |s|
          values.include?(s)
        end
      end
    end
    if respond_to?(:match) && match
      must "match pattern #{match.inspect}" do |s|
        #p [:matching, s, da.match.inspect]
        s.to_s =~ match
      end
    end
    instance_eval(&type_block) if type_block
  end
end

#date(name, params = { }, &block) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/doodle/datatypes.rb', line 157

def date(name, params = { }, &block)
  datatype name, params, block, { :kind => Date } do
    from String do |s|
      Date.parse(s)
    end
    from Array do |y,m,d|
      Date.new(y, m, d)
    end
    from Integer do |jd|
      Date.new(*Date.jd_to_civil(jd))
    end
  end
end

#dictionary(name, params = { }, &block) ⇒ Object

Raises:

  • (ArgumentError)


230
231
232
233
234
235
236
237
# File 'lib/doodle/datatypes.rb', line 230

def dictionary(name, params = { }, &block)
  if name.kind_of?(Class)
    params[:collect] = name
    name = Doodle::Utils.pluralize(Doodle::Utils.snake_case(name))
  end
  raise ArgumentError, "#{name} must specify what to :collect", [caller[-1]] if !params.key?(:collect)
  datatype name, params, block, { :using => Doodle::KeyedAttribute }
end

#email(name, params = { }, &block) ⇒ Object



147
148
149
150
151
152
153
154
155
# File 'lib/doodle/datatypes.rb', line 147

def email(name, params = { }, &block)
  # for max length, see http://www.imc.org/ietf-fax/archive2/msg01578.html
  # 384 = 128+1+255
  string(name, { :max => 384 }.merge(params), &block).instance_eval do
    must "be valid email address" do |s|
      s =~ RFC822::EmailAddress
    end
  end
end

#integer(name, params = { }, &block) ⇒ Object



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
# File 'lib/doodle/datatypes.rb', line 45

def integer(name, params = { }, &block)
  if params.key?(:max)
    max = params.delete(:max)
  end
  if params.key?(:min)
    min = params.delete(:min)
  end
  datatype name, params, block, { :kind => Integer } do
    from Float do |n|
      n.to_i
    end
    from String do |n|
      n =~ /[0-9]+(.[0-9]+)?/ or raise ArgumentError, "#{name} must be numeric", [caller[-1]]
      n.to_i
    end
    if max
      must "be <= #{max}" do |s|
        s.size <= max
      end
    end
    if min
      must "be >= #{min}" do |s|
        s.size >= min
      end
    end
  end
end

#list(name, params = { }, &block) ⇒ Object

Raises:

  • (ArgumentError)


221
222
223
224
225
226
227
228
# File 'lib/doodle/datatypes.rb', line 221

def list(name, params = { }, &block)
  if name.kind_of?(Class)
    params[:collect] = name
    name = Doodle::Utils.pluralize(Doodle::Utils.snake_case(name))
  end
  raise ArgumentError, "#{name} must specify what to :collect", [caller[-1]] if !params.key?(:collect)
  datatype name, params, block, { :using => Doodle::AppendableAttribute }
end

#string(name, params = { }, &block) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/doodle/datatypes.rb', line 105

def string(name, params = { }, &block)
  # must extract non-standard attributes before processing with
  # datatype otherwise causes UnknownAttribute error in Attribute definition
  if params.key?(:max)
    max = params.delete(:max)
  end
  if params.key?(:size)
    size = params.delete(:size)
    # size should be a Range
    size.kind_of?(Range) or raise ArgumentError, "#{name}: size should be a Range", [caller[-1]]
  end
  datatype name, params, block, { :kind => String } do
    from String do |s|
      s
    end
    from Integer do |i|
      i.to_s
    end
    from Symbol do |s|
      s.to_s
    end
    if max
      must "be <= #{max} characters" do |s|
        s.size <= max
      end
    end
    if size
      must "have size from #{size} characters" do |s|
        size.include?(s.size)
      end
    end
  end
end

#symbol(name, params = { }, &block) ⇒ Object



97
98
99
100
101
102
103
# File 'lib/doodle/datatypes.rb', line 97

def symbol(name, params = { }, &block)
  datatype name, params, block, { :kind => Symbol } do
    from String do |s|
      s.to_sym
    end
  end
end

#time(name, params = { }, &block) ⇒ Object

defaults to UTC if passed an array use :timezone => :local if you want local time



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/doodle/datatypes.rb', line 173

def time(name, params = { }, &block)
  timezone_method = params.delete(:timezone) || :utc
  if timezone_method == :local
    timezone_method = :mktime
  end
  datatype name, params, block, { :kind => Time } do
    from String do |s|
      Time.parse(s)
    end
    from Array do |*args|
      Time.send(timezone_method, *args)
    end
    # seconds since Thu Jan 01 00:00:00 UTC 1970
    from Integer do |epoch_seconds|
      Time.at(epoch_seconds)
    end
  end
end

#uri(name, params = { }, &block) ⇒ Object



139
140
141
142
143
144
145
# File 'lib/doodle/datatypes.rb', line 139

def uri(name, params = { }, &block)
  datatype name, params, block, { :kind => URI } do
    from String do |s|
      URI.parse(s)
    end
  end
end

#utc(name, params = { }, &block) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/doodle/datatypes.rb', line 194

def utc(name, params = { }, &block)
  da = time( name, { :kind => Time }.merge(params))
  da.instance_eval do
    # override time from String
    from String do |s|
      if s !~ RX_ISODATE
        raise ArgumentError, "date must be in ISO format (YYYY-MM-DDTHH:MM:SS, e.g. #{Time.now.utc.xmlschema})"
      end
      Time.parse(s)
    end
  end
  da.instance_eval(&block) if block_given?
  da
end

#version(name, params = { }, &block) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
# File 'lib/doodle/datatypes.rb', line 209

def version(name, params = { }, &block)
  datatype name, params, block, { :kind => String } do
    must "be of form n.n.n" do |str|
      str =~ /\d+\.\d+.\d+/
    end
    from Array do |a|
      a.size == 3 or raise ArgumentError, "#{name}: version array argument must contain exactly 3 elements", [caller[-1]]
      a.join('.')
    end
  end
end