ixtlan-babel 0.1.2 → 0.2.0
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.
- data/Gemfile.lock +9 -5
- data/README.md +5 -1
- data/lib/ixtlan/babel/abstract_filter.rb +26 -0
- data/lib/ixtlan/babel/abstract_filter.rb~ +111 -0
- data/lib/ixtlan/babel/config.rb~ +142 -0
- data/lib/ixtlan/babel/context.rb +43 -0
- data/lib/ixtlan/babel/context.rb~ +43 -0
- data/lib/ixtlan/babel/deserializer.rb +21 -19
- data/lib/ixtlan/babel/factory.rb +27 -12
- data/lib/ixtlan/babel/filter_config.rb +52 -0
- data/lib/ixtlan/babel/filter_config.rb~ +111 -0
- data/lib/ixtlan/babel/hash_filter.rb +17 -123
- data/lib/ixtlan/babel/hash_filter.rb- +170 -0
- data/lib/ixtlan/babel/hash_filter.rb~ +111 -0
- data/lib/ixtlan/babel/hash_only_filter.rb~ +142 -0
- data/lib/ixtlan/babel/model_filter.rb +53 -0
- data/lib/ixtlan/babel/model_filter.rb~ +170 -0
- data/lib/ixtlan/babel/no_timestamp_serializer.rb +3 -7
- data/lib/ixtlan/babel/serializer.rb +44 -20
- data/spec/hash_filter_spec.rb +99 -0
- data/spec/{filter_spec.rb → hash_filter_spec.rb~} +0 -0
- data/spec/model_filter_spec.rb +163 -0
- data/spec/model_filter_spec.rb~ +99 -0
- data/spec/model_filter_with_methods.spec.rb~ +167 -0
- data/spec/model_filter_with_methods_spec.rb +184 -0
- data/spec/model_filter_with_methods_spec.rb~ +170 -0
- metadata +82 -81
data/Gemfile.lock
CHANGED
@@ -6,15 +6,19 @@ PATH
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
8
8
|
specs:
|
9
|
+
backports (2.6.2)
|
9
10
|
json_pure (1.6.1)
|
10
|
-
minitest (
|
11
|
-
rake (0.
|
11
|
+
minitest (4.3.2)
|
12
|
+
rake (10.0.2)
|
13
|
+
virtus (0.5.1)
|
14
|
+
backports (~> 2.6.1)
|
12
15
|
|
13
16
|
PLATFORMS
|
14
17
|
ruby
|
15
18
|
|
16
19
|
DEPENDENCIES
|
17
20
|
ixtlan-babel!
|
18
|
-
json_pure (~> 1.6
|
19
|
-
minitest (
|
20
|
-
rake (
|
21
|
+
json_pure (~> 1.6)
|
22
|
+
minitest (~> 4.3.0)
|
23
|
+
rake (~> 10.0.0)
|
24
|
+
virtus (~> 0.5.0)
|
data/README.md
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# babel #
|
2
|
+
|
3
|
+
* [](http://travis-ci.org/mkristian/babel)
|
4
|
+
* [](https://gemnasium.com/mkristian/ixtlan-babel)
|
5
|
+
* [](https://codeclimate.com/github/mkristian/ixtlan-babel)
|
2
6
|
|
3
7
|
rails comes with `to_json` and `to_xml` on models and you can give them an option map to control how the whole object tree gets serialized.
|
4
8
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ixtlan/babel/context'
|
2
|
+
module Ixtlan
|
3
|
+
module Babel
|
4
|
+
class AbstractFilter
|
5
|
+
|
6
|
+
attr_accessor :options
|
7
|
+
|
8
|
+
def options
|
9
|
+
@options || {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_custom_serializers( map )
|
13
|
+
@map = map
|
14
|
+
end
|
15
|
+
|
16
|
+
def serialize( data )
|
17
|
+
if @map && ser = @map[ data.class.to_s ]
|
18
|
+
ser.call(data)
|
19
|
+
else
|
20
|
+
data
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'ixtlan/babel/context'
|
2
|
+
module Ixtlan
|
3
|
+
module Babel
|
4
|
+
class HashFilter
|
5
|
+
|
6
|
+
def initialize(context_or_options = nil)
|
7
|
+
use(context_or_options)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# def context
|
13
|
+
# @context ||= {}
|
14
|
+
# end
|
15
|
+
|
16
|
+
public
|
17
|
+
|
18
|
+
def add_custom_serializers( map )
|
19
|
+
@map = map
|
20
|
+
end
|
21
|
+
|
22
|
+
# def default_context_key( single = :single,
|
23
|
+
# collection = :collection )
|
24
|
+
# @single, @collection = single, collection
|
25
|
+
# end
|
26
|
+
|
27
|
+
# def []=( key, options )
|
28
|
+
# context[ key.to_sym ] = options if key
|
29
|
+
# end
|
30
|
+
|
31
|
+
# def []( key )
|
32
|
+
# context[ key.to_sym ] if key
|
33
|
+
# end
|
34
|
+
|
35
|
+
def use( context_or_options )
|
36
|
+
# if context_or_options
|
37
|
+
# case context_or_options
|
38
|
+
# when Symbol
|
39
|
+
# if opts = context[ context_or_options ]
|
40
|
+
# @options = opts.dup
|
41
|
+
# end
|
42
|
+
# when Hash
|
43
|
+
@options = context_or_options
|
44
|
+
# end
|
45
|
+
# else
|
46
|
+
# @options = nil
|
47
|
+
# end
|
48
|
+
# self
|
49
|
+
end
|
50
|
+
|
51
|
+
def filter( data )
|
52
|
+
if data
|
53
|
+
filter_data( data,
|
54
|
+
Context.new( @options || {} ) )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# def single_options
|
59
|
+
# @options || context[default_context_key[0]] || {}
|
60
|
+
# end
|
61
|
+
|
62
|
+
# def collection_options
|
63
|
+
# @options || context[default_context_key[1]] || {}
|
64
|
+
# end
|
65
|
+
|
66
|
+
# def root
|
67
|
+
# @root ||= single_options.key?(:root) ? single_options[:root].to_s : nil
|
68
|
+
# end
|
69
|
+
|
70
|
+
# private
|
71
|
+
|
72
|
+
# def options_for( hash )
|
73
|
+
# @options || (hash.is_a?(Array) ? collection_options : single_options)
|
74
|
+
# end
|
75
|
+
|
76
|
+
def filter_array( array, options )
|
77
|
+
array.collect do |item|
|
78
|
+
if item.is_a?( Array ) || item.is_a?( Hash )
|
79
|
+
filter_data( item, options )
|
80
|
+
else
|
81
|
+
item
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def serialize( data )
|
87
|
+
if @map && ser = @map[ data.class.to_s ]
|
88
|
+
ser.call(data)
|
89
|
+
else
|
90
|
+
data
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def filter_data( data, context )
|
95
|
+
result = {}
|
96
|
+
data.each do |k,v|
|
97
|
+
k = k.to_s
|
98
|
+
case v
|
99
|
+
when Hash
|
100
|
+
result[ k ] = filter_data( v, context[ k ] ) if context.include?( k )
|
101
|
+
when Array
|
102
|
+
result[ k ] = filter_array( v, context[ k ] ) if context.include?( k )
|
103
|
+
else
|
104
|
+
result[ k ] = serialize( v ) if context.allowed?( k )
|
105
|
+
end
|
106
|
+
end
|
107
|
+
result
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Ixtlan
|
2
|
+
module Babel
|
3
|
+
class HashFilter
|
4
|
+
|
5
|
+
def initialize(context_or_options = nil)
|
6
|
+
use(context_or_options)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def context
|
12
|
+
@context ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
public
|
16
|
+
|
17
|
+
def add_custom_serializers(map)
|
18
|
+
@map = map
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_context_key( single = :single,
|
22
|
+
collection = :collection )
|
23
|
+
@single, @collection = single, collection
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=( key, options )
|
27
|
+
context[ key.to_sym ] = options if key
|
28
|
+
end
|
29
|
+
|
30
|
+
def []( key )
|
31
|
+
context[ key.to_sym ] if key
|
32
|
+
end
|
33
|
+
|
34
|
+
def use( context_or_options )
|
35
|
+
if context_or_options
|
36
|
+
case context_or_options
|
37
|
+
when Symbol
|
38
|
+
if opts = context[ context_or_options ]
|
39
|
+
@options = opts.dup
|
40
|
+
end
|
41
|
+
when Hash
|
42
|
+
@options = context_or_options
|
43
|
+
end
|
44
|
+
else
|
45
|
+
@options = nil
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def filter(hash = {}, model = nil, &block)
|
51
|
+
if hash
|
52
|
+
filter_data( hash,
|
53
|
+
Config.new( options_for( hash ) ),
|
54
|
+
&block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def options_for( hash )
|
59
|
+
@options || (hash.is_a?(Array) ? collection_options : single_options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def single_options
|
63
|
+
@options || context[default_context_key[0]] || {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def collection_options
|
67
|
+
@options || context[default_context_key[1]] || {}
|
68
|
+
end
|
69
|
+
|
70
|
+
def root
|
71
|
+
@root ||= single_options.key?(:root) ? single_options[:root].to_s : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
class Config
|
77
|
+
|
78
|
+
def initialize( options )
|
79
|
+
@only = options[ :only ].collect { |o| o.to_s } if options[ :only ]
|
80
|
+
@except = ( options[:except] || [] ).collect { |e| e.to_s }
|
81
|
+
|
82
|
+
opts = options[ :include ]
|
83
|
+
@include =
|
84
|
+
case opts
|
85
|
+
when Array
|
86
|
+
opts.collect { |i| i.to_s }
|
87
|
+
when Hash
|
88
|
+
Hash[ opts.collect { |k,v| [ k.to_s, v ] } ]
|
89
|
+
else
|
90
|
+
[]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def allowed?( key )
|
95
|
+
( @only && @only.include?( key ) ) || ( @only.nil? && !@except.include?( key ) )
|
96
|
+
end
|
97
|
+
|
98
|
+
def include?( key )
|
99
|
+
@include.include? key
|
100
|
+
end
|
101
|
+
|
102
|
+
def []( key )
|
103
|
+
self.class.new( @include.is_a?( Array ) ? {} : @include[ key ] )
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def filter_array( array, options )
|
108
|
+
array.collect do |item|
|
109
|
+
if item.is_a?( Array ) || item.is_a?( Hash )
|
110
|
+
filter_data( item, options )
|
111
|
+
else
|
112
|
+
item
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def serialize( data )
|
118
|
+
if @map && ser = @map[ data.class.to_s ]
|
119
|
+
ser.call(data)
|
120
|
+
else
|
121
|
+
data
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def filter_data( data, config )
|
126
|
+
result = {}
|
127
|
+
data.each do |k,v|
|
128
|
+
k = k.to_s
|
129
|
+
case v
|
130
|
+
when Hash
|
131
|
+
result[ k ] = filter_data( v, config[ k ] ) if config.include?( k )
|
132
|
+
when Array
|
133
|
+
result[ k ] = filter_array( v, config[ k ] ) if config.include?( k )
|
134
|
+
else
|
135
|
+
result[ k ] = serialize( v ) if config.allowed?( k )
|
136
|
+
end
|
137
|
+
end
|
138
|
+
result
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Ixtlan
|
2
|
+
module Babel
|
3
|
+
class Context
|
4
|
+
|
5
|
+
def initialize( options )
|
6
|
+
@only = options[ :only ].collect { |o| o.to_s } if options[ :only ]
|
7
|
+
@except = ( options[:except] || [] ).collect { |e| e.to_s }
|
8
|
+
|
9
|
+
opts = options[ :include ]
|
10
|
+
@include = case opts
|
11
|
+
when Array
|
12
|
+
opts.collect { |i| i.to_s }
|
13
|
+
when Hash
|
14
|
+
Hash[ opts.collect { |k,v| [ k.to_s, v ] } ]
|
15
|
+
else
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
@methods = (options[:methods] || []).collect { |m| m.to_s }
|
19
|
+
end
|
20
|
+
|
21
|
+
def methods
|
22
|
+
@methods + ( @include.is_a?( Array ) ? @include : @include.keys )
|
23
|
+
end
|
24
|
+
|
25
|
+
def allowed?( key )
|
26
|
+
( @only && @only.include?( key ) ) || ( @only.nil? && !@except.include?( key ) ) || @methods.include?( key )
|
27
|
+
end
|
28
|
+
|
29
|
+
def include?( key )
|
30
|
+
@include.include? key
|
31
|
+
end
|
32
|
+
|
33
|
+
def array?
|
34
|
+
@include.is_a?( Array )
|
35
|
+
end
|
36
|
+
|
37
|
+
def []( key )
|
38
|
+
self.class.new( @include.is_a?( Array ) ? {} : @include[ key ] )
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Ixtlan
|
2
|
+
module Babel
|
3
|
+
class Config
|
4
|
+
|
5
|
+
def initialize( options )
|
6
|
+
@only = options[ :only ].collect { |o| o.to_s } if options[ :only ]
|
7
|
+
@except = ( options[:except] || [] ).collect { |e| e.to_s }
|
8
|
+
|
9
|
+
opts = options[ :include ]
|
10
|
+
@include = case opts
|
11
|
+
when Array
|
12
|
+
opts.collect { |i| i.to_s }
|
13
|
+
when Hash
|
14
|
+
Hash[ opts.collect { |k,v| [ k.to_s, v ] } ]
|
15
|
+
else
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
@methods = (options[:methods] || []).collect { |m| m.to_s }
|
19
|
+
end
|
20
|
+
|
21
|
+
def methods
|
22
|
+
@methods + ( @include.is_a?( Array ) ? @include : @include.keys )
|
23
|
+
end
|
24
|
+
|
25
|
+
def allowed?( key )
|
26
|
+
( @only && @only.include?( key ) ) || ( @only.nil? && !@except.include?( key ) ) || @methods.include?( key )
|
27
|
+
end
|
28
|
+
|
29
|
+
def include?( key )
|
30
|
+
@include.include? key
|
31
|
+
end
|
32
|
+
|
33
|
+
def array?
|
34
|
+
@include.is_a?( Array )
|
35
|
+
end
|
36
|
+
|
37
|
+
def []( key )
|
38
|
+
self.class.new( @include.is_a?( Array ) ? {} : @include[ key ] )
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -8,46 +8,48 @@ module Ixtlan
|
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
def self.
|
12
|
-
@
|
11
|
+
def self.config
|
12
|
+
@config ||= FilterConfig.new
|
13
13
|
end
|
14
14
|
|
15
15
|
def filter
|
16
|
-
@filter ||=
|
16
|
+
@filter ||= HashFilter.new
|
17
17
|
end
|
18
18
|
|
19
19
|
protected
|
20
20
|
|
21
21
|
def self.default_context_key(default)
|
22
|
-
|
22
|
+
config.default_context_key(default)
|
23
23
|
end
|
24
24
|
|
25
25
|
def self.add_context(key, options = {})
|
26
|
-
|
26
|
+
config[key] = options
|
27
27
|
end
|
28
28
|
|
29
29
|
public
|
30
30
|
|
31
31
|
def use(context_or_options)
|
32
|
-
|
32
|
+
@context_or_options = context_or_options
|
33
33
|
self
|
34
34
|
end
|
35
|
+
|
36
|
+
def from_array_hash( data )
|
37
|
+
if filter.options[:root]
|
38
|
+
data.collect{ |d| @model_class.new( filter.filter( d[ filter.options[:root] ] ) ) }
|
39
|
+
else
|
40
|
+
data.collect{ |d| @model_class.new( filter.filter( d ) ) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
private :from_array_hash
|
35
44
|
|
36
45
|
def from_hash(data, options = nil)
|
37
|
-
filter.
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
data.collect{ |d| @model_class.new(filter.filter(d[root])) }
|
42
|
-
else
|
43
|
-
@model_class.new(filter.filter(data[root.to_s]))
|
44
|
-
end
|
46
|
+
filter.options = options || {}
|
47
|
+
filter.options[:root] ||= self.class.config.root
|
48
|
+
if data.is_a? Array
|
49
|
+
from_array_hash( data )
|
45
50
|
else
|
46
|
-
|
47
|
-
|
48
|
-
else
|
49
|
-
@model_class.new(filter.filter(data))
|
50
|
-
end
|
51
|
+
data = data[ filter.options[:root] ] if filter.options[:root]
|
52
|
+
@model_class.new( filter.filter( data ) )
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|