Class: Praxis::ActionDefinition

Inherits:
Object
  • Object
show all
Defined in:
lib/praxis.rb,
lib/praxis/action_definition.rb,
lib/praxis/action_definition/headers_dsl_compiler.rb

Defined Under Namespace

Classes: HeadersDSLCompiler

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, resource_definition, **opts, &block) ⇒ ActionDefinition

Returns a new instance of ActionDefinition.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/praxis/action_definition.rb', line 33

def initialize(name, resource_definition, **opts, &block)
  @name = name
  @resource_definition = resource_definition
  @responses = Hash.new
  @metadata = Hash.new
  @routes = []

  if (media_type = resource_definition.media_type)
    if media_type.kind_of?(Class) && media_type < Praxis::Types::MediaTypeCommon
      @reference_media_type = media_type
    end
  end

  resource_definition.action_defaults.each do |defaults|
    self.instance_eval(&defaults)
  end

  self.instance_eval(&block) if block_given?
end

Class Attribute Details

.doc_decorationsObject

Returns the value of attribute doc_decorations.



24
25
26
# File 'lib/praxis/action_definition.rb', line 24

def doc_decorations
  @doc_decorations
end

Instance Attribute Details

#metadataObject (readonly)

opaque hash of user-defined medata, used to decorate the definition, and also available in the generated JSON documents



21
22
23
# File 'lib/praxis/action_definition.rb', line 21

def 
  @metadata
end

#nameObject (readonly)

Returns the value of attribute name.



12
13
14
# File 'lib/praxis/action_definition.rb', line 12

def name
  @name
end

#named_routesObject (readonly)

Returns the value of attribute named_routes.



16
17
18
# File 'lib/praxis/action_definition.rb', line 16

def named_routes
  @named_routes
end

#primary_routeObject (readonly)

Returns the value of attribute primary_route.



15
16
17
# File 'lib/praxis/action_definition.rb', line 15

def primary_route
  @primary_route
end

#resource_definitionObject (readonly)

Returns the value of attribute resource_definition.



13
14
15
# File 'lib/praxis/action_definition.rb', line 13

def resource_definition
  @resource_definition
end

#responsesObject (readonly)

Returns the value of attribute responses.



17
18
19
# File 'lib/praxis/action_definition.rb', line 17

def responses
  @responses
end

#routesObject (readonly)

Returns the value of attribute routes.



14
15
16
# File 'lib/praxis/action_definition.rb', line 14

def routes
  @routes
end

Class Method Details

.decorate_docs(&callback) ⇒ Object



29
30
31
# File 'lib/praxis/action_definition.rb', line 29

def self.decorate_docs(&callback)
  self.doc_decorations << callback
end

Instance Method Details

#create_attribute(type = Attributor::Struct, **opts, &block) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/praxis/action_definition.rb', line 63

def create_attribute(type=Attributor::Struct, **opts, &block)
  unless opts[:reference]
    opts[:reference] = @reference_media_type if @reference_media_type && block
  end

  return Attributor::Attribute.new(type, opts, &block)
end

#describeObject



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

def describe
  {}.tap do |hash|
    hash[:description] = description
    hash[:name] = name
    hash[:metadata] = 
    # FIXME: change to :routes along with api browser
    hash[:urls] = routes.collect(&:describe)
    hash[:headers] = headers.describe if headers
    if params
      hash[:params] = params_description
    end
    hash[:payload] = payload.describe if payload
    hash[:responses] = responses.inject({}) do |memo, (response_name, response)|
      memo[response.name] = response.describe
      memo
    end
    self.class.doc_decorations.each do |callback|
      callback.call(self, hash)
    end
  end
end

#description(text = nil) ⇒ Object



147
148
149
150
# File 'lib/praxis/action_definition.rb', line 147

def description(text = nil)
  @description = text if text
  @description
end

#headers(type = nil, **opts, &block) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/praxis/action_definition.rb', line 108

def headers(type=nil, **opts, &block)
  return @headers unless block
  if @headers
    update_attribute(@headers, opts, block)
  else
    type = Attributor::Hash.of(key:String) unless type
    @headers = create_attribute(type,
      dsl_compiler: HeadersDSLCompiler, case_insensitive_load: true,
      **opts, &block)
  end
  @precomputed_header_keys_for_rack = nil #clear memoized data
end

#nodoc!Object



198
199
200
# File 'lib/praxis/action_definition.rb', line 198

def nodoc!
  [:doc_visibility] = :none
end

#params(type = Attributor::Struct, **opts, &block) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/praxis/action_definition.rb', line 78

def params(type=Attributor::Struct, **opts, &block)
  return @params if !block && type == Attributor::Struct

  if @params
    unless type == Attributor::Struct && @params.type < Attributor::Struct
      raise Exceptions::InvalidConfiguration.new(
        "Invalid type received for extending params: #{type.name}"
      )
    end
    update_attribute(@params, opts, block)
  else
    @params = create_attribute(type, **opts, &block)
  end
end

#params_descriptionObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/praxis/action_definition.rb', line 175

def params_description
  route_params = []
  if primary_route.nil?
    warn "Warning: No routes defined for #{resource_definition.name}##{name}."
  else
    route_params = primary_route.path.
      named_captures.
      keys.
      collect(&:to_sym)
  end

  desc = params.describe
  desc[:type][:attributes].keys.each do |k|
    source = if route_params.include? k
      'url'
    else
      'query'
    end
    desc[:type][:attributes][k][:source] = source
  end
  desc
end

#payload(type = Attributor::Struct, **opts, &block) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/praxis/action_definition.rb', line 93

def payload(type=Attributor::Struct, **opts, &block)
  return @payload if !block && type == Attributor::Struct

  if @payload
    unless type == Attributor::Struct && @payload.type < Attributor::Struct
      raise Exceptions::InvalidConfiguration.new(
        "Invalid type received for extending params: #{type.name}"
      )
    end
    update_attribute(@payload, opts, block)
  else
    @payload = create_attribute(type, **opts, &block)
  end
end

#precomputed_header_keys_for_rackObject

Good optimization to avoid creating lots of strings and comparisons on a per-request basis. However, this is hacky, as it is rack-specific, and does not really belong here



124
125
126
127
128
129
130
131
132
# File 'lib/praxis/action_definition.rb', line 124

def precomputed_header_keys_for_rack
  @precomputed_header_keys_for_rack ||= begin
    @headers.attributes.keys.each_with_object(Hash.new) do |key,hash|
      name = key.to_s
      name = "HTTP_#{name.gsub('-','_').upcase}" unless ( name == "CONTENT_TYPE" || name == "CONTENT_LENGTH" )
      hash[name] = key
    end
  end
end

#response(name, **args) ⇒ Object



58
59
60
61
# File 'lib/praxis/action_definition.rb', line 58

def response( name, **args )
  template = ApiDefinition.instance.response(name)
  @responses[name] = template.compile(self, **args)
end

#routing(&block) ⇒ Object



135
136
137
138
139
140
141
142
143
144
# File 'lib/praxis/action_definition.rb', line 135

def routing(&block)
  routing_config = Skeletor::RestfulRoutingConfig.new(name, resource_definition, &block)

  @routes = routing_config.routes
  @primary_route = routing_config.routes.first
  @named_routes = routing_config.routes.each_with_object({}) do |route, hash|
    next if route.name.nil?
    hash[route.name] = route
  end
end

#update_attribute(attribute, options, block) ⇒ Object



53
54
55
56
# File 'lib/praxis/action_definition.rb', line 53

def update_attribute(attribute, options, block)
  attribute.options.merge!(options)
  attribute.type.attributes(options, &block)
end

#use(trait_name) ⇒ Object



71
72
73
74
75
76
# File 'lib/praxis/action_definition.rb', line 71

def use(trait_name)
  unless ApiDefinition.instance.traits.has_key? trait_name
    raise Exceptions::InvalidTrait.new("Trait #{trait_name} not found in the system")
  end
  self.instance_eval(&ApiDefinition.instance.traits[trait_name])
end