Module: Shapeable::Shape

Defined in:
lib/shapeable/shape.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(klass) ⇒ Object



5
6
7
# File 'lib/shapeable/shape.rb', line 5

def self.included(klass)
  klass.extend Shapeable::Extenders
end

Instance Method Details

#construct_constant(path, shape: nil, version: nil) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/shapeable/shape.rb', line 89

def construct_constant(path, shape: nil, version: nil)
  resource = infer_resource_name(path)
  if shape && version
    path.const_get("V#{version}::#{resource}#{shape.camelize}Serializer")
  elsif shape
    path.const_get("#{resource}#{shape.camelize}Serializer")
  elsif version
    path.const_get("V#{version}::#{resource}Serializer")
  else
    path.const_get("#{resource}Serializer")
  end
rescue NameError
  raise Shapeable::Errors::InvalidShapeError.new(path, shape, version: version)
end

#infer_resource_name(path) ⇒ Object



104
105
106
# File 'lib/shapeable/shape.rb', line 104

def infer_resource_name(path)
  path.name.split('::').last.constantize
end

#merge_shapeable_options(*opts) ⇒ Object



24
25
26
27
28
# File 'lib/shapeable/shape.rb', line 24

def merge_shapeable_options(*opts)
  opts.each_with_object({}) do |val, obj|
    obj.merge!(val)
  end
end

#normalize_shapeable_options!(opts) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/shapeable/shape.rb', line 30

def normalize_shapeable_options!(opts)
  opts.keep_if do |k, _|
    [
      :path,
      :default_shape,
      :default_version,
      :shape,
      :version,
      :enforce_versioning,
      :enforce_shape
    ].include?(k)
  end
end

#request_shape_options(request, shape_attr_name, version_attr_name) ⇒ Object



63
64
65
66
67
68
# File 'lib/shapeable/shape.rb', line 63

def request_shape_options(request, shape_attr_name, version_attr_name)
  {
    version: resolve_header_version(request.accept, version_attr_name) || resolve_params_version(request.params, version_attr_name),
    shape: resolve_header_shape(request.accept, shape_attr_name) || resolve_params_shape(request.params, shape_attr_name)
  }.delete_if { |_, v| v.blank? }
end

#resolve_header_shape(accept_header, shape_attr_name) ⇒ Object



77
78
79
# File 'lib/shapeable/shape.rb', line 77

def resolve_header_shape(accept_header, shape_attr_name)
  accept_header[/#{shape_attr_name}\s?=\s?(\w+)/, 1] if accept_header
end

#resolve_header_version(accept_header, version_attr_name) ⇒ Object



70
71
72
73
74
75
# File 'lib/shapeable/shape.rb', line 70

def resolve_header_version(accept_header, version_attr_name)
  if accept_header
    version_str = accept_header[/#{version_attr_name}\s?=\s?(\d+)/, 1]
    version_str.nil? ? nil : version_str.to_i
  end
end

#resolve_params_shape(params, shape_attr_name) ⇒ Object



85
86
87
# File 'lib/shapeable/shape.rb', line 85

def resolve_params_shape(params, shape_attr_name)
  params[shape_attr_name]
end

#resolve_params_version(params, version_attr_name) ⇒ Object



81
82
83
# File 'lib/shapeable/shape.rb', line 81

def resolve_params_version(params, version_attr_name)
  params[version_attr_name]
end

#shape(default_shape_opts = {}) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/shapeable/shape.rb', line 9

def shape(default_shape_opts = {})
  opts = merge_shapeable_options(
    Shapeable.configuration.as_json,
    acts_as_shapeable_opts,
    default_shape_opts,
    request_shape_options(
      request,
      Shapeable.configuration.as_json[:shape_attr_override] || 'shape',
      Shapeable.configuration.as_json[:version_attr_override] || 'version',
    )
  )
  normalize_shapeable_options!(opts)
  validate_and_resolve_shape(opts)
end

#validate_and_resolve_shape(opts) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/shapeable/shape.rb', line 44

def validate_and_resolve_shape(opts)
  version = opts[:version] || opts[:default_version]
  shape = opts[:shape] || opts[:default_shape]

  if opts[:path].blank?
    raise Shapeable::Errors::UnresolvedPathError
  elsif opts[:enforce_versioning] && version.blank?
    raise Shapeable::Errors::UnresolvedVersionError
  elsif opts[:enforce_shape] && shape.nil?
    raise Shapeable::Errors::UnresolvedShapeError
  end

  if opts[:enforce_versioning]
    construct_constant(opts[:path], shape: shape, version: version)
  else
    construct_constant(opts[:path], shape: shape)
  end
end