Class: Dao::Api

Inherits:
Object
  • Object
show all
Defined in:
lib/dao/api.rb,
lib/dao/api/dsl.rb,
lib/dao/api/modes.rb,
lib/dao/api/routes.rb,
lib/dao/api/endpoints.rb,
lib/dao/api/interfaces.rb,
lib/dao/api/initializers.rb

Defined Under Namespace

Classes: DSL

Constant Summary collapse

Initializers =
{}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_mode(mode) ⇒ Object



14
15
16
17
18
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
44
45
46
# File 'lib/dao/api/modes.rb', line 14

def add_mode(mode)
  mode = Mode.for(mode)

  unless modes.include?(mode)
    module_eval(<<-__, __FILE__, __LINE__ - 1)
      def #{ mode }(*args, &block)
        if args.empty?
          if catching_results?
            if self.mode.case_of?(Mode.for(#{ mode.inspect }))
              mode(#{ mode.inspect }, &block)
              return!
            end
          else
            mode(#{ mode.inspect }, &block)
          end
        else
          mode(#{ mode.inspect }) do
            call(*args, &block)
          end
        end
      end

      def #{ mode }?(&block)
        mode?(#{ mode.inspect }, &block)
      end
    __

    modes.push(mode)
    mode
  else
    false
  end
end

.after_initializer(&block) ⇒ Object



33
34
35
# File 'lib/dao/api/initializers.rb', line 33

def after_initializer(&block)
  after_initializers.push(block)
end

.after_initializersObject



29
30
31
# File 'lib/dao/api/initializers.rb', line 29

def after_initializers
  initializers[:after]
end

.before_initializer(&block) ⇒ Object



23
24
25
26
27
# File 'lib/dao/api/initializers.rb', line 23

def before_initializer(&block)
  method_name = "before_initializer_#{ before_initializers.size }"
  define_method(method_name, &block)
  before_initializers.push(method_name)
end

.before_initializersObject



19
20
21
# File 'lib/dao/api/initializers.rb', line 19

def before_initializers
  initializers[:before]
end

.description(string) ⇒ Object Also known as: desc



29
30
31
# File 'lib/dao/api/endpoints.rb', line 29

def description(string)
  doc(:description => Dao.unindent(string))
end

.doc(*args) ⇒ Object



34
35
36
37
38
39
40
41
42
43
# File 'lib/dao/api/endpoints.rb', line 34

def doc(*args)
  docs.push(Map[:description, nil]) if docs.empty?
  doc = docs.last
  options = Dao.options_for!(args)
  if options.empty?
    options[:description] = args.join(' ')
  end
  doc.update(options)
  doc
end

.docsObject



45
46
47
# File 'lib/dao/api/endpoints.rb', line 45

def docs
  @docs ||= []
end

.endpoint(path, &block) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/dao/api/endpoints.rb', line 8

def endpoint(path, &block)
  api = self
  path = Path.new(path)

  method =
    module_eval{ 
      define_method(path + '/endpoint', &block)
      instance_method(path + '/endpoint')
    }


  endpoint = Endpoint.new(
    'api' => api,
    'path' => path,
    'method' => method,
    'doc' => docs.pop
  )

  endpoints[path] = endpoint
end

.endpointsObject



4
5
6
# File 'lib/dao/api/endpoints.rb', line 4

def endpoints
  @endpoints ||= Map.new
end

.evaluate(&block) ⇒ Object



34
35
36
37
# File 'lib/dao/api/dsl.rb', line 34

def evaluate(&block)
  @dsl ||= DSL.new(api=self)
  @dsl.evaluate(&block)
end

.indexObject



49
50
51
52
53
54
55
# File 'lib/dao/api/endpoints.rb', line 49

def index
  index = Map.new
  endpoints.each do |path, endpoint|
    index[path] = endpoint.doc || {'description' => path}
  end
  index
end

.initializersObject



15
16
17
# File 'lib/dao/api/initializers.rb', line 15

def initializers
  Initializers[self] ||= {:before => [], :after => []}
end

.interface(path, &block) ⇒ Object Also known as: call



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/dao/api/interfaces.rb', line 10

def interface(path, &block)
  api = self
  path = Path.new(path)

  route = routes.add(path) if Route.like?(path)

  method =
    module_eval{ 
      define_method(path + '/interface', &block)
      instance_method(path + '/interface')
    }

  interface = Interface.new(
    'api' => api,
    'path' => path,
    'route' => route,
    'method' => method,
    'doc' => docs.pop
  )

  interfaces[path] = interface
end

.interfacesObject



6
7
8
# File 'lib/dao/api/interfaces.rb', line 6

def interfaces
  @interfaces ||= Map.new
end

.modes(*modes) ⇒ Object



4
5
6
7
8
# File 'lib/dao/api/modes.rb', line 4

def modes(*modes)
  @modes ||= []
  modes.flatten.compact.map{|mode| Api.add_mode(mode)} unless modes.empty?
  @modes
end

.modes=(*modes) ⇒ Object



10
11
12
# File 'lib/dao/api/modes.rb', line 10

def modes=(*modes)
  modes(*modes)
end

.new(*args, &block) ⇒ Object



6
7
8
9
10
11
12
13
# File 'lib/dao/api/initializers.rb', line 6

def new(*args, &block)
  allocate.instance_eval do
    before_initializers(*args, &block)
    initialize(*args, &block)
    after_initializers(*args, &block)
    self
  end
end

.routesObject



4
5
6
# File 'lib/dao/api/routes.rb', line 4

def routes
  @routes ||= Route::List.new
end

.superclassesObject



37
38
39
# File 'lib/dao/api/initializers.rb', line 37

def superclasses
  @superclasses ||= ancestors.select{|ancestor| ancestor <= Dao::Api}
end

Instance Method Details

#after_initialize(*args, &block) ⇒ Object



67
68
69
# File 'lib/dao/api/initializers.rb', line 67

def after_initialize(*args, &block)
  :hook
end

#after_initializers(*args, &block) ⇒ Object



59
60
61
# File 'lib/dao/api/initializers.rb', line 59

def after_initializers(*args, &block)
  run_initializers(:after, *args, &block)
end

#before_initialize(*args, &block) ⇒ Object



63
64
65
# File 'lib/dao/api/initializers.rb', line 63

def before_initialize(*args, &block)
  :hook
end

#before_initializers(*args, &block) ⇒ Object



55
56
57
# File 'lib/dao/api/initializers.rb', line 55

def before_initializers(*args, &block)
  run_initializers(:before, *args, &block)
end

#call(path = '/index', params = {}, options = {}) ⇒ Object

call support



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/dao/api/interfaces.rb', line 69

def call(path = '/index', params = {})
  api = self
  path = Path.new(path)
  endpoint = endpoints[path]
  raise(NameError, path) unless endpoint

  params = parse_params(params, path)

  context = Context.new(
    :api => api,
    :endpoint => endpoint,
    :params => params
  )

  callstack(context) do
    catching(:result){ context.call() }
  end

  context.result
end

#callstack(context = nil, &block) ⇒ Object

context support



114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/dao/api/interfaces.rb', line 114

def callstack(context = nil, &block)
  @callstack ||= []

  if block and context
    begin
      @callstack.push(context)
      return block.call()
    ensure
      @callstack.pop
    end
  else
    @callstack
  end
end

#catching(label = :result, &block) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/dao/api/endpoints.rb', line 159

def catching(label = :result, &block)
  @catching ||= []

  if block
    begin
      @catching.push(label)
      catch(label, &block)
    ensure
      @catching.pop
    end
  else
    @catching.last
  end
end

#catching?Boolean

Returns:

  • (Boolean)


178
179
180
# File 'lib/dao/api/endpoints.rb', line 178

def catching?
  catching
end

#catching_results(&block) ⇒ Object



174
175
176
# File 'lib/dao/api/endpoints.rb', line 174

def catching_results(&block)
  catching(:result, &block)
end

#catching_results?Boolean

Returns:

  • (Boolean)


182
183
184
# File 'lib/dao/api/endpoints.rb', line 182

def catching_results?
  catching == :result
end

#contextObject



96
97
98
# File 'lib/dao/api/endpoints.rb', line 96

def context
  callstack.last
end

#context?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/dao/api/interfaces.rb', line 133

def context?
  !!callstack.last
end

#data(*args) ⇒ Object



108
109
110
# File 'lib/dao/api/endpoints.rb', line 108

def data
  result.data
end

#data!(*args) ⇒ Object



191
192
193
194
# File 'lib/dao/api/interfaces.rb', line 191

def data!(*args)
  data(*args)
  valid!
end

#endpointsObject



92
93
94
# File 'lib/dao/api/endpoints.rb', line 92

def endpoints
  self.class.endpoints
end

#error!Object



201
202
203
# File 'lib/dao/api/interfaces.rb', line 201

def error!
  result.error!
end

#errorsObject



112
113
114
# File 'lib/dao/api/endpoints.rb', line 112

def errors
  result.errors
end

#indexObject

misc



217
218
219
# File 'lib/dao/api/interfaces.rb', line 217

def index
  self.class.index
end

#interfacesObject



221
222
223
# File 'lib/dao/api/interfaces.rb', line 221

def interfaces
  self.class.interfaces
end

#mode(*args, &block) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/dao/api/modes.rb', line 53

def mode(*args, &block)
  @mode ||= Mode.default

  if args.empty? and block.nil?
    @mode
  else
    if block
      mode = self.mode
      self.mode = args.shift
      begin
        return(instance_eval(&block))
      ensure
        self.mode = mode
      end
    else
      self.mode = args.shift
      return(self)
    end
  end
end

#mode=(mode) ⇒ Object



49
50
51
# File 'lib/dao/api/modes.rb', line 49

def mode=(mode)
  @mode = Mode.for(mode)
end

#mode?(mode, &block) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
# File 'lib/dao/api/modes.rb', line 74

def mode?(mode, &block)
  condition = mode.case_of?(self.mode)
  if block.nil?
    condition
  else
    send(mode, &block) if condition
  end
end

#parameter(*args, &block) ⇒ Object Also known as: param

immediate parameter parsing support

Raises:

  • (ArgumentError)


231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/dao/api/interfaces.rb', line 231

def parameter(*args, &block)
  options = Map.options_for!(args)

  keys = args + Array(options[:keys]) + Array(options[:or])

  raise(ArgumentError, 'no keys') if keys.empty?

  blank = Object.new.freeze
  value = blank

  keys.each do |key|
    if params.has?(key)
      value = params.get(key)
      break unless value.to_s.strip.empty?
    end
  end

  if value == blank
    message =
      case options[:error]
        when nil, false
          nil
        when true
          which = keys.map{|key| Array(key).join('.')}.join(' or ')
          "#{ which } (parameter is blank)"
        else
          message = options[:error].to_s
      end
    errors.add(message) if message

    status(options[:status]) if options[:status]
    return! if options[:return!]
  end

  value == blank ? nil : value
end

#parameter!(*args, &block) ⇒ Object Also known as: param!



269
270
271
272
273
274
275
276
# File 'lib/dao/api/interfaces.rb', line 269

def parameter!(*args, &block)
  options = args.last.is_a?(Hash) ? Map.for(args.pop) : Map.new
  args.push(options)
  options[:error] = true unless options.has_key?(:error)
  options[:return!] = true unless options.has_key?(:return!)
  options[:status] = 412 unless options.has_key?(:status)
  parameter(*args, &block)
end

#paramsObject



116
117
118
# File 'lib/dao/api/endpoints.rb', line 116

def params
  result.params
end

#params!(*args) ⇒ Object



196
197
198
199
# File 'lib/dao/api/interfaces.rb', line 196

def params!(*args)
  params.replace(*args)
  valid!
end

#parse_params(params, path) ⇒ Object



83
84
85
86
87
88
89
90
# File 'lib/dao/api/endpoints.rb', line 83

def parse_params(params, path)
  return params if params.is_a?(Params)
  re = %r/^#{ Regexp.escape(path) }/
  params.each do |key, val|
    return Params.parse(path, params) if key =~ re
  end
  return params
end

#respond_to?(*args) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
# File 'lib/dao/api/endpoints.rb', line 186

def respond_to?(*args)
  super(*args) || super(Path.absolute_path_for(*args))
end

#resultObject



100
101
102
# File 'lib/dao/api/endpoints.rb', line 100

def result
  context.result
end

#return!(*value) ⇒ Object



152
153
154
# File 'lib/dao/api/interfaces.rb', line 152

def return!(*value)
  throw(:result, *value)
end

#route_for(*args) ⇒ Object

lookup a route



108
109
110
# File 'lib/dao/api/interfaces.rb', line 108

def route_for(*args)
  self.class.routes.match(*args)
end

#run_initializers(which, *args, &block) ⇒ Object



46
47
48
49
50
51
52
53
# File 'lib/dao/api/initializers.rb', line 46

def run_initializers(which, *args, &block)
  superclasses.each do |superclass|
    superclass.send("#{ which }_initializers").each do |method_name|
      send(method_name, *args, &block)
    end
  end
  send("#{ which }_initialize", *args, &block)
end

#status(*args) ⇒ Object



104
105
106
# File 'lib/dao/api/endpoints.rb', line 104

def status(*args, &block)
  result.status(*args, &block)
end

#status!(*args) ⇒ Object



182
183
184
185
# File 'lib/dao/api/interfaces.rb', line 182

def status!(*args)
  status.update(*args)
  return!
end

#superclassesObject



42
43
44
# File 'lib/dao/api/initializers.rb', line 42

def superclasses
  @superclasses ||= self.class.superclasses
end

#valid!Object



140
141
142
# File 'lib/dao/api/endpoints.rb', line 140

def valid!
  result.valid!
end

#valid?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/dao/api/endpoints.rb', line 132

def valid?
  result.valid?
end

#validateObject



128
129
130
# File 'lib/dao/api/endpoints.rb', line 128

def validate
  result.validate
end

#validate!Object



136
137
138
# File 'lib/dao/api/endpoints.rb', line 136

def validate!
  result.validate!
end

#validates(*args, &block) ⇒ Object



124
125
126
# File 'lib/dao/api/endpoints.rb', line 124

def validates(*args, &block)
  result.validates(*args, &block)
end

#validationsObject



120
121
122
# File 'lib/dao/api/endpoints.rb', line 120

def validations
  result.validations
end