typero 0.9.0 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.version +1 -1
- data/lib/adapters/sequel.rb +10 -27
- data/lib/typero.rb +2 -1
- data/lib/typero/params.rb +33 -6
- data/lib/typero/schema.rb +36 -14
- data/lib/typero/type/type.rb +17 -2
- data/lib/typero/type/types/date_type.rb +4 -1
- data/lib/typero/type/types/datetime_type.rb +3 -1
- data/lib/typero/type/types/hash_type.rb +9 -3
- data/lib/typero/type/types/locale_type.rb +13 -0
- data/lib/typero/type/types/model_type.rb +7 -5
- data/lib/typero/type/types/time_type.rb +5 -0
- data/lib/typero/type/types/timezone_type.rb +15 -0
- data/lib/typero/typero.rb +32 -24
- metadata +8 -6
- data/lib/typero/exporter.rb +0 -93
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b0ee2233c2ba484ec5ff98778a8da24a876b7b22eb4d24cc6b3ba3a8886e714
|
4
|
+
data.tar.gz: 4a96d10f9c6d0e75e8ae36965d34a6cda8853684974f799e2cf5e32d6a7003c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 880c3e4e551ab660f85530454ad9007ae383118677ea209ffaf0efff54bcd38da220579dc42d87618bd9ea50790b04a46c63dfe3cfd6252508b2bbec6ba1d711
|
7
|
+
data.tar.gz: 6f10437b894c91f3c7f723da03b426218d60b21c8bd161111d8ae7a745bdf35565f4fba84f26552fc75aa9b40211f3902d1cc2418fc420a5e3bce912ac676bc2
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.3
|
data/lib/adapters/sequel.rb
CHANGED
@@ -3,60 +3,43 @@
|
|
3
3
|
module Sequel::Plugins::TyperoAttributes
|
4
4
|
module ClassMethods
|
5
5
|
def typero
|
6
|
-
Typero.
|
6
|
+
Typero.schema self
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
module InstanceMethods
|
11
11
|
# calling typero! on any object will validate all fields
|
12
|
-
def
|
13
|
-
|
12
|
+
def validate
|
13
|
+
super
|
14
14
|
|
15
|
-
|
15
|
+
schema = Typero.schema(self.class) || return
|
16
16
|
|
17
|
-
|
17
|
+
schema.validate(self) do |name, err|
|
18
18
|
errors.add(name, err) unless (errors.on(name) || []).include?(err)
|
19
19
|
end
|
20
20
|
|
21
21
|
# this are rules unique to database, so we check them here
|
22
|
-
|
23
|
-
self[field] ||= {} if rule[:type] == 'hash'
|
24
|
-
|
22
|
+
schema.rules.each do |field, rule|
|
25
23
|
# check uniqe fields
|
26
|
-
if rule
|
24
|
+
if unique = rule.dig(:meta, :unique)
|
27
25
|
id = self[:id] || 0
|
28
26
|
value = self[field]
|
29
27
|
|
30
28
|
# we only check if field is changed
|
31
29
|
if value.present? && column_changed?(field) && self.class.xwhere('LOWER(%s)=LOWER(?) and id<>?' % field, value, id).first
|
32
|
-
error =
|
30
|
+
error = unique.class == TrueClass ? %[Value '"#{value}"' for #{field} allready exists] : unique
|
33
31
|
errors.add(field, error) unless (errors.on(field) || []).include?(error)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
# check protected fields
|
38
|
-
if rule
|
36
|
+
if prot = rule.dig(:meta, :protected) && self[:id]
|
39
37
|
if column_changed?(field)
|
40
|
-
error =
|
38
|
+
error = prot.class == TrueClass ? "value once defined can't be overwritten." : prot
|
41
39
|
errors.add(field, error) unless (errors.on(field) || []).include?(error)
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
45
|
-
|
46
|
-
# check single field if single field given
|
47
|
-
if field_name
|
48
|
-
raise ArgumentError.new 'Field :%s not found in %s' % [field_name, self] unless self[field_name]
|
49
|
-
return unless errors.on(field_name)
|
50
|
-
|
51
|
-
errors.on(field_name).join(', ')
|
52
|
-
end
|
53
|
-
|
54
|
-
true
|
55
|
-
end
|
56
|
-
|
57
|
-
def validate
|
58
|
-
typero!
|
59
|
-
super
|
60
43
|
end
|
61
44
|
end
|
62
45
|
|
data/lib/typero.rb
CHANGED
data/lib/typero/params.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Typero
|
4
4
|
class Params
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :db_rules
|
6
6
|
|
7
7
|
def initialize &block
|
8
8
|
@db_rules = []
|
@@ -10,10 +10,14 @@ module Typero
|
|
10
10
|
instance_exec &block
|
11
11
|
end
|
12
12
|
|
13
|
+
def rules
|
14
|
+
@rules.dup
|
15
|
+
end
|
16
|
+
|
13
17
|
private
|
14
18
|
|
15
19
|
# used in dsl to define schema field options
|
16
|
-
def set field, *args
|
20
|
+
def set field, *args, &block
|
17
21
|
raise "Field name not given (Typero)" unless field
|
18
22
|
|
19
23
|
if args.first.is_a?(Hash)
|
@@ -27,13 +31,29 @@ module Typero
|
|
27
31
|
|
28
32
|
field = field.to_s
|
29
33
|
|
34
|
+
if field.include?('!')
|
35
|
+
if block
|
36
|
+
field = field.sub('!', '')
|
37
|
+
@block_type = field.to_sym
|
38
|
+
instance_exec &block
|
39
|
+
@block_type = nil
|
40
|
+
return
|
41
|
+
else
|
42
|
+
raise ArgumentError.new 'If you use ! you have to provide a block'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
30
46
|
# name? - opional name
|
31
47
|
if field.include?('?')
|
32
48
|
field = field.sub('?', '')
|
33
49
|
opts[:required] = false
|
34
50
|
end
|
35
51
|
|
36
|
-
|
52
|
+
if value = opts.delete(:req)
|
53
|
+
opts[:required] = value
|
54
|
+
else
|
55
|
+
opts[:required] = true if opts[:required].nil?
|
56
|
+
end
|
37
57
|
|
38
58
|
# array that allows duplicates
|
39
59
|
if opts[:type].is_a?(Array)
|
@@ -47,12 +67,14 @@ module Typero
|
|
47
67
|
opts[:array] = true
|
48
68
|
end
|
49
69
|
|
70
|
+
opts[:type] = @block_type if @block_type
|
71
|
+
|
50
72
|
# Boolean
|
51
|
-
if opts[:type].is_a?(TrueClass)
|
73
|
+
if opts[:type].is_a?(TrueClass) || opts[:type] == :true
|
52
74
|
opts[:required] = false
|
53
75
|
opts[:default] = true
|
54
76
|
opts[:type] = :boolean
|
55
|
-
elsif opts[:type].is_a?(FalseClass)
|
77
|
+
elsif opts[:type].is_a?(FalseClass) || opts[:type] == :false
|
56
78
|
opts[:required] = false
|
57
79
|
opts[:default] = false
|
58
80
|
opts[:type] = :boolean
|
@@ -61,6 +83,11 @@ module Typero
|
|
61
83
|
opts[:model] = opts.delete(:schema) if opts[:schema]
|
62
84
|
opts[:type] = :model if opts[:model]
|
63
85
|
|
86
|
+
if block_given?
|
87
|
+
opts[:type] = :model
|
88
|
+
opts[:model] = Typero.schema &block
|
89
|
+
end
|
90
|
+
|
64
91
|
opts[:type] ||= 'string'
|
65
92
|
opts[:type] = opts[:type].to_s.downcase.to_sym
|
66
93
|
|
@@ -93,7 +120,7 @@ module Typero
|
|
93
120
|
# set :emails, Array[:email]
|
94
121
|
# email Array[:emails]
|
95
122
|
def method_missing field, *args, &block
|
96
|
-
set field, *args
|
123
|
+
set field, *args, &block
|
97
124
|
end
|
98
125
|
end
|
99
126
|
end
|
data/lib/typero/schema.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Typero
|
2
2
|
class Schema
|
3
3
|
SCHEMAS = {}
|
4
|
+
TYPES = {}
|
4
5
|
|
5
6
|
# accepts dsl block to
|
6
7
|
def initialize &block
|
@@ -10,11 +11,22 @@ module Typero
|
|
10
11
|
|
11
12
|
# validates any instance object with hash variable interface
|
12
13
|
# it also coarces values
|
13
|
-
def validate object
|
14
|
-
@
|
15
|
-
@
|
14
|
+
def validate object, options=nil
|
15
|
+
@options = options || {}
|
16
|
+
@object = object
|
17
|
+
@errors = {}
|
18
|
+
|
19
|
+
# remove undefined keys if Hash provided
|
20
|
+
if @options[:strict] && object.is_a?(Hash)
|
21
|
+
undefined = object.keys.map(&:to_s) - @schema.rules.keys.map(&:to_s)
|
22
|
+
object.delete_if { |k, _| undefined.include?(k.to_s) }
|
23
|
+
end
|
16
24
|
|
17
25
|
@schema.rules.each do |field, opts|
|
26
|
+
for k in opts.keys
|
27
|
+
opts[k] = @object.instance_exec(&opts[k]) if opts[k].is_a?(Proc)
|
28
|
+
end
|
29
|
+
|
18
30
|
# set value to default if value is blank and default given
|
19
31
|
@object[field] = opts[:default] if opts[:default] && @object[field].blank?
|
20
32
|
|
@@ -22,32 +34,36 @@ module Typero
|
|
22
34
|
value = @object[field]
|
23
35
|
|
24
36
|
if opts[:array]
|
25
|
-
unless value.
|
26
|
-
opts[:delimiter] ||= /\s
|
37
|
+
unless value.respond_to?(:each)
|
38
|
+
opts[:delimiter] ||= /\s*[,\n]\s*/
|
27
39
|
value = value.to_s.split(opts[:delimiter])
|
28
40
|
end
|
29
41
|
|
30
42
|
value = value
|
31
|
-
.
|
32
|
-
.map { |el| el.to_s == '' ? nil : el }
|
43
|
+
.flatten
|
44
|
+
.map { |el| el.to_s == '' ? nil : check_filed_value(field, el, opts) }
|
33
45
|
.compact
|
34
46
|
|
35
47
|
value = Set.new(value).to_a unless opts[:duplicates]
|
36
48
|
|
37
49
|
opts[:max_count] ||= 100
|
38
|
-
add_error(field, 'Max number of array elements is %d, you have %d' % [opts[:max_count], value.length], opts) if value.length > opts[:max_count]
|
50
|
+
add_error(field, 'Max number of array elements is %d, you have %d' % [opts[:max_count], value.length], opts) if value && value.length > opts[:max_count]
|
51
|
+
add_error(field, 'Min number of array elements is %d, you have %d' % [opts[:min_count], value.length], opts) if value && opts[:min_count] && value.length < opts[:min_count]
|
39
52
|
|
40
53
|
add_required_error field, value.first, opts
|
41
54
|
else
|
55
|
+
value = nil if value.to_s == ''
|
56
|
+
|
57
|
+
# if value is not list of allowed values, raise error
|
58
|
+
allowed = opts[:allow] || opts[:allowed] || opts[:values]
|
59
|
+
if value && allowed && !allowed.include?(value)
|
60
|
+
add_error field, 'Value "%s" is not allowed' % value, opts
|
61
|
+
end
|
62
|
+
|
42
63
|
value = check_filed_value field, value, opts
|
43
64
|
add_required_error field, value, opts
|
44
65
|
end
|
45
66
|
|
46
|
-
# if value is not list of allowed values, raise error
|
47
|
-
if opts[:allowed] && !opts[:values].include?(value)
|
48
|
-
add_error field, 'Value "%s" is not allowed' % value, opts
|
49
|
-
end
|
50
|
-
|
51
67
|
# present empty string values as nil
|
52
68
|
@object[field] = value.to_s.sub(/\s+/, '') == '' ? nil : value
|
53
69
|
end
|
@@ -126,7 +142,13 @@ module Typero
|
|
126
142
|
check = klass.constantize.new value, opts
|
127
143
|
check.get
|
128
144
|
rescue TypeError => e
|
129
|
-
|
145
|
+
if e.message[0] == '{'
|
146
|
+
for key, msg in JSON.parse(e.message)
|
147
|
+
add_error [field, key].join('.'), msg, opts
|
148
|
+
end
|
149
|
+
else
|
150
|
+
add_error field, e.message, opts
|
151
|
+
end
|
130
152
|
end
|
131
153
|
end
|
132
154
|
end
|
data/lib/typero/type/type.rb
CHANGED
@@ -15,8 +15,23 @@ module Typero
|
|
15
15
|
}
|
16
16
|
|
17
17
|
# default shared allowed opts keys
|
18
|
-
OPTS_KEYS = [:type, :required, :array, :max_count, :default, :name, :meta, :model]
|
19
18
|
OPTS = {}
|
19
|
+
OPTS_KEYS = [
|
20
|
+
:allow,
|
21
|
+
:allowed,
|
22
|
+
:array,
|
23
|
+
:default,
|
24
|
+
:description,
|
25
|
+
:max_count,
|
26
|
+
:meta,
|
27
|
+
:min_count,
|
28
|
+
:model,
|
29
|
+
:name,
|
30
|
+
:req,
|
31
|
+
:required,
|
32
|
+
:type,
|
33
|
+
:values
|
34
|
+
]
|
20
35
|
|
21
36
|
attr_reader :opts
|
22
37
|
|
@@ -48,7 +63,7 @@ module Typero
|
|
48
63
|
###
|
49
64
|
|
50
65
|
def initialize value, opts={}, &block
|
51
|
-
value = value.
|
66
|
+
value = value.strip.rstrip if value.is_a?(String)
|
52
67
|
|
53
68
|
@value = value
|
54
69
|
@opts = opts
|
@@ -3,7 +3,10 @@ class Typero::DateType < Typero::Type
|
|
3
3
|
error :en, :max_date, 'Maximal allowed date is %s'
|
4
4
|
|
5
5
|
def set
|
6
|
-
|
6
|
+
unless [Date].include?(value.class)
|
7
|
+
value { |data| DateTime.parse(data) }
|
8
|
+
end
|
9
|
+
|
7
10
|
value { |data| DateTime.new(data.year, data.month, data.day) }
|
8
11
|
|
9
12
|
check_date_min_max
|
@@ -2,11 +2,17 @@ class Typero::HashType < Typero::Type
|
|
2
2
|
error :en, :not_hash_type_error, 'value is not hash type'
|
3
3
|
|
4
4
|
def set
|
5
|
-
|
5
|
+
if value.is_a?(String) && value[0,1] == '{'
|
6
|
+
@value = JSON.load(value)
|
7
|
+
end
|
8
|
+
|
9
|
+
@value ||= {}
|
10
|
+
|
11
|
+
error_for(:not_hash_type_error) unless @value.respond_to?(:keys) && @value.respond_to?(:values)
|
6
12
|
|
7
13
|
if opts[:allow]
|
8
|
-
for key in value.keys
|
9
|
-
value.delete(key) unless opts[:allow].include?(key)
|
14
|
+
for key in @value.keys
|
15
|
+
@value.delete(key) unless opts[:allow].include?(key)
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Typero::LocaleType < Typero::Type
|
2
|
+
error :en, :locale_bad_format, 'Locale "%s" is in bad format (should be xx or xx-xx)'
|
3
|
+
|
4
|
+
def set
|
5
|
+
error_for(:locale_bad_format, value) unless value =~ /^[\w\-]{2,5}$/
|
6
|
+
end
|
7
|
+
|
8
|
+
def db_schema
|
9
|
+
[:string, { limit: 5 }]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -2,14 +2,16 @@ class Typero::ModelType < Typero::Type
|
|
2
2
|
def set
|
3
3
|
value(&:to_h)
|
4
4
|
|
5
|
-
errors =
|
5
|
+
errors = {}
|
6
6
|
|
7
|
-
schema = Typero.schema(opts[:model])
|
8
|
-
|
9
|
-
|
7
|
+
schema = opts[:model].is_a?(Typero::Schema) ? opts[:model] : Typero.schema(opts[:model])
|
8
|
+
|
9
|
+
# by default models in schems are strict true (remove undefined keys)
|
10
|
+
schema.validate value, strict: true do |field, error|
|
11
|
+
errors[field] = error
|
10
12
|
end
|
11
13
|
|
12
|
-
raise TypeError.new errors.
|
14
|
+
raise TypeError.new errors.to_json if errors.keys.first
|
13
15
|
end
|
14
16
|
|
15
17
|
def db_schema
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Typero::TimezoneType < Typero::Type
|
2
|
+
error :en, :invalid_time_zone, 'Invalid time zone'
|
3
|
+
|
4
|
+
def set
|
5
|
+
TZInfo::Timezone.get(value)
|
6
|
+
rescue TZInfo::InvalidTimezoneIdentifier
|
7
|
+
error_for :invalid_time_zone
|
8
|
+
end
|
9
|
+
|
10
|
+
def db_schema
|
11
|
+
[:string, { length: 50 }]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
data/lib/typero/typero.rb
CHANGED
@@ -35,29 +35,40 @@ module Typero
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
# load type schema
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
# load or set type schema
|
39
|
+
# Typero.schema(:blog) { ... }
|
40
|
+
# Typero.schema(:blog, type: :model) { ... }
|
41
|
+
# Typero.schema(:blog)
|
42
|
+
# Typero.schema(type: :model)
|
43
|
+
def schema name=nil, opts=nil, &block
|
44
|
+
klass = name.to_s.classify if name && !name.is_a?(Hash)
|
42
45
|
|
43
46
|
if block_given?
|
44
47
|
Typero::Schema.new(&block).tap do |schema|
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
raise ArgumentErorr.new('Schema name not given') unless name
|
48
|
+
if klass
|
49
|
+
Typero::Schema::SCHEMAS[klass] = schema
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def export model, opts={}, &block
|
57
|
-
if block_given?
|
58
|
-
Exporter::EXPORTERS[model.to_s.classify] = block
|
51
|
+
if opts && opts[:type]
|
52
|
+
Typero::Schema::TYPES[opts[:type]] ||= []
|
53
|
+
Typero::Schema::TYPES[opts[:type]].push klass unless Typero::Schema::TYPES[opts[:type]].include?(klass)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
59
57
|
else
|
60
|
-
|
58
|
+
# Schema not given, get schema
|
59
|
+
if name.is_a?(Hash)
|
60
|
+
# Typero.schema type: :model
|
61
|
+
if type = name[:type]
|
62
|
+
Typero::Schema::TYPES[type]
|
63
|
+
end
|
64
|
+
elsif klass
|
65
|
+
# Typero.schema :user
|
66
|
+
schema = Typero::Schema::SCHEMAS[klass]
|
67
|
+
schema ||= class_finder klass, :schema
|
68
|
+
schema || nil
|
69
|
+
else
|
70
|
+
raise ArgumentError, 'Schema type not defined.'
|
71
|
+
end
|
61
72
|
end
|
62
73
|
end
|
63
74
|
|
@@ -78,13 +89,10 @@ module Typero
|
|
78
89
|
for el in args
|
79
90
|
for separator in ['_','/']
|
80
91
|
klass = [name, el].join(separator).classify
|
81
|
-
|
82
|
-
begin
|
83
|
-
return klass.constantize
|
84
|
-
rescue NameError => e
|
85
|
-
nil
|
86
|
-
end
|
92
|
+
return klass.constantize if const_defined? klass
|
87
93
|
end
|
88
94
|
end
|
95
|
+
|
96
|
+
nil
|
89
97
|
end
|
90
98
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dino Reic
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fast_blank
|
@@ -34,7 +34,6 @@ files:
|
|
34
34
|
- "./.version"
|
35
35
|
- "./lib/adapters/sequel.rb"
|
36
36
|
- "./lib/typero.rb"
|
37
|
-
- "./lib/typero/exporter.rb"
|
38
37
|
- "./lib/typero/params.rb"
|
39
38
|
- "./lib/typero/schema.rb"
|
40
39
|
- "./lib/typero/type/type.rb"
|
@@ -48,18 +47,21 @@ files:
|
|
48
47
|
- "./lib/typero/type/types/image_type.rb"
|
49
48
|
- "./lib/typero/type/types/integer_type.rb"
|
50
49
|
- "./lib/typero/type/types/label_type.rb"
|
50
|
+
- "./lib/typero/type/types/locale_type.rb"
|
51
51
|
- "./lib/typero/type/types/model_type.rb"
|
52
52
|
- "./lib/typero/type/types/oib_type.rb"
|
53
53
|
- "./lib/typero/type/types/point_type.rb"
|
54
54
|
- "./lib/typero/type/types/string_type.rb"
|
55
55
|
- "./lib/typero/type/types/text_type.rb"
|
56
|
+
- "./lib/typero/type/types/time_type.rb"
|
57
|
+
- "./lib/typero/type/types/timezone_type.rb"
|
56
58
|
- "./lib/typero/type/types/url_type.rb"
|
57
59
|
- "./lib/typero/typero.rb"
|
58
60
|
homepage: https://github.com/dux/typero
|
59
61
|
licenses:
|
60
62
|
- MIT
|
61
63
|
metadata: {}
|
62
|
-
post_install_message:
|
64
|
+
post_install_message:
|
63
65
|
rdoc_options: []
|
64
66
|
require_paths:
|
65
67
|
- lib
|
@@ -75,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
77
|
version: '0'
|
76
78
|
requirements: []
|
77
79
|
rubygems_version: 3.0.6
|
78
|
-
signing_key:
|
80
|
+
signing_key:
|
79
81
|
specification_version: 4
|
80
82
|
summary: Ruby type system
|
81
83
|
test_files: []
|
data/lib/typero/exporter.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
module Typero
|
2
|
-
class Exporter
|
3
|
-
EXPORTERS ||= {}
|
4
|
-
|
5
|
-
attr_accessor :response
|
6
|
-
|
7
|
-
def initialize model, opts={}
|
8
|
-
opts = { user: opts } unless opts.is_a?(Hash)
|
9
|
-
|
10
|
-
opts[:exporter] ||= model.class
|
11
|
-
opts[:depth] ||= 1
|
12
|
-
opts[:current_depth] ||= 0
|
13
|
-
|
14
|
-
exporter = opts.delete(:exporter).to_s.classify
|
15
|
-
|
16
|
-
@model = model
|
17
|
-
@opts = opts
|
18
|
-
@block = EXPORTERS[exporter] || raise('Exporter "%s" (:%s) not found' % [block, block.underscore])
|
19
|
-
@response = {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def render
|
23
|
-
instance_exec &@block
|
24
|
-
@response
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def export object, opts={}
|
30
|
-
if object.is_a?(Symbol)
|
31
|
-
return property object, export(model.send(object))
|
32
|
-
end
|
33
|
-
|
34
|
-
return if @opts[:current_depth] >= @opts[:depth]
|
35
|
-
|
36
|
-
@opts[:current_depth] += 1
|
37
|
-
out = self.class.new(object, @opts.merge(opts)).render
|
38
|
-
@opts[:current_depth] -= 1
|
39
|
-
out
|
40
|
-
end
|
41
|
-
|
42
|
-
def property name, data=:_undefined
|
43
|
-
if block_given?
|
44
|
-
data = yield if data == :_undefined
|
45
|
-
@response[name] = data
|
46
|
-
else
|
47
|
-
data = data == :_undefined ? model.send(name) : data
|
48
|
-
|
49
|
-
if data.respond_to?(:export_json)
|
50
|
-
data = data.export_json
|
51
|
-
elsif data.respond_to?(:to_h)
|
52
|
-
data = data.to_h
|
53
|
-
end
|
54
|
-
|
55
|
-
@response[name] = data
|
56
|
-
end
|
57
|
-
end
|
58
|
-
alias :prop :property
|
59
|
-
|
60
|
-
def hproperty name
|
61
|
-
@response[name] = model[name]
|
62
|
-
end
|
63
|
-
alias :hprop :hproperty
|
64
|
-
|
65
|
-
def namespace name, &block
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def meta &block
|
70
|
-
namespace :meta, &block
|
71
|
-
end
|
72
|
-
|
73
|
-
def model
|
74
|
-
@model
|
75
|
-
end
|
76
|
-
|
77
|
-
# get current user from globals if globals defined
|
78
|
-
def user
|
79
|
-
if @opts[:user]
|
80
|
-
@opts[:user]
|
81
|
-
elsif defined?(User) && User.respond_to?(:current)
|
82
|
-
User.current
|
83
|
-
elsif defined?(Current) && Current.respond_to?(:user)
|
84
|
-
Current.user
|
85
|
-
elsif current_user = Thread.current[:current_user]
|
86
|
-
current_user
|
87
|
-
else
|
88
|
-
nil
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|