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.
@@ -0,0 +1,111 @@
1
+ require 'ixtlan/babel/config'
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( hash = {} )
52
+ if hash
53
+ filter_data( hash,
54
+ Config.new( options_for( hash ) ) )
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, config )
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, config[ k ] ) if config.include?( k )
101
+ when Array
102
+ result[ k ] = filter_array( v, config[ k ] ) if config.include?( k )
103
+ else
104
+ result[ k ] = serialize( v ) if config.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,53 @@
1
+ require 'ixtlan/babel/abstract_filter'
2
+ module Ixtlan
3
+ module Babel
4
+ class ModelFilter < AbstractFilter
5
+
6
+ def filter( model, &block )
7
+ if model
8
+ data = block.call( model )
9
+ filter_data( model, data,
10
+ Context.new( options ),
11
+ &block )
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def filter_array( models, options, &block )
18
+ models.collect do |i|
19
+ if i.respond_to? :attributes
20
+ filter_data(i, block.call(i), options, &block)
21
+ else
22
+ i
23
+ end
24
+ end
25
+ end
26
+
27
+ def setup_data(model, data, context)
28
+ context.methods.each do |m|
29
+ unless data.include?(m)
30
+ data[ m ] = model.send( m.to_sym )
31
+ end
32
+ end
33
+ end
34
+
35
+ def filter_data(model, data, context, &block)
36
+ setup_data(model, data, context)
37
+
38
+ result = {}
39
+ data.each do |k,v|
40
+ k = k.to_s
41
+ if v.respond_to? :attributes
42
+ result[ k ] = filter_data( v, block.call(v), context[ k ], &block ) if context.include?( k )
43
+ elsif v.is_a? Array
44
+ result[ k ] = filter_array( v, context[ k ], &block ) if context.include?( k )
45
+ else
46
+ result[ k ] = serialize( v ) if context.allowed?( k ) && ! v.respond_to?( :attributes )
47
+ end
48
+ end
49
+ result
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,170 @@
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, collection = :collection)
22
+ @single, @collection = single, collection
23
+ end
24
+
25
+ def []=(key, options)
26
+ context[key.to_sym] = options if key
27
+ end
28
+
29
+ def [](key)
30
+ context[key.to_sym] if key
31
+ end
32
+
33
+ def use(context_or_options)
34
+ if context_or_options
35
+ case context_or_options
36
+ when Symbol
37
+ if opts = context[context_or_options]
38
+ @options = opts.dup
39
+ end
40
+ when Hash
41
+ @options = context_or_options
42
+ end
43
+ else
44
+ @options = nil
45
+ end
46
+ self
47
+ end
48
+
49
+ NO_MODEL = Object.new
50
+ def NO_MODEL.send(*args)
51
+ self
52
+ end
53
+ def NO_MODEL.[](*args)
54
+ self
55
+ end
56
+
57
+ def filter(hash = {}, model = NO_MODEL, &block)
58
+ filter_data(model, hash, hash.is_a?(Array) ? collection_options : single_options, &block) if hash
59
+ end
60
+
61
+ def single_options
62
+ @options || context[default_context_key[0]] || {}
63
+ end
64
+
65
+ def collection_options
66
+ @options || context[default_context_key[1]] || {}
67
+ end
68
+
69
+ def root
70
+ @root ||= single_options.key?(:root) ? single_options[:root].to_s : nil
71
+ end
72
+
73
+ private
74
+
75
+ def filter_data(model, data, options = {}, &block)
76
+ model = NO_MODEL if model == data
77
+ only = options[:only].collect { |o| o.to_s } if options[:only]
78
+ except = (options[:except] || []).collect { |e| e.to_s }
79
+
80
+ include =
81
+ case options[:include]
82
+ when Array
83
+ options[:include].collect { |i| i.to_s }
84
+ when Hash
85
+ Hash[options[:include].collect {|k,v| [k.to_s, v]}]
86
+ else
87
+ []
88
+ end
89
+ if model != NO_MODEL
90
+ methods = (options[:methods] || []).collect { |e| e.to_s }
91
+ methods.each do |m|
92
+ data[m] = model.send(m.to_sym)
93
+ end
94
+
95
+ include_methods = include.is_a?(Array) ? include : include.keys
96
+ include_methods.each do |m|
97
+ unless data.include?(m)
98
+ raise "no block given to calculate the attributes from model" unless block
99
+ models_or_model = model.send(m)
100
+ if models_or_model.is_a?(Array) && models_or_model.first.is_a?(String)
101
+ data[m] = models_or_model
102
+ elsif models_or_model.respond_to?(:collect)
103
+ data[m] = models_or_model.collect { |i| block.call(i) }
104
+ else
105
+ val = model.send(m)
106
+ case val
107
+ when Fixnum
108
+ data[m] = val
109
+ when String
110
+ data[m] = val
111
+ when TrueClass
112
+ data[m] = val
113
+ else
114
+ data[m]= block.call(val)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ methods ||= []
121
+ result = {}
122
+ data.each do |k,v|
123
+ case v
124
+ when Hash
125
+ if include.include?(k.to_s)
126
+ case include
127
+ when Array
128
+ result[k.to_s] = filter_data(model.send(k), v, &block)
129
+ when Hash
130
+ result[k.to_s] = filter_data(model.send(k), v, include[k.to_s], &block)
131
+ end
132
+ end
133
+ when Array
134
+ if include.include?(k.to_s)
135
+ models = model.send(k)
136
+ j = -1
137
+ case include
138
+ when Array
139
+ result[k.to_s] = v.collect do |i|
140
+ j += 1
141
+ if i.is_a?(Array) || i.is_a?(Hash)
142
+ filter_data(models[j], i, &block)
143
+ else
144
+ i
145
+ end
146
+ end
147
+ when Hash
148
+ opts = include[k.to_s]
149
+ result[k.to_s] = v.collect do |i|
150
+ j += 1
151
+ ndata = i.is_a?(Hash)? i : block.call(i)
152
+ filter_data(models[j], ndata, opts, &block)
153
+ end
154
+ end
155
+ end
156
+ else
157
+ if methods.include?(k.to_s) || (only && only.include?(k.to_s)) || (only.nil? && !except.include?(k.to_s))
158
+ if @map && ser = @map[v.class.to_s]
159
+ result[k.to_s] = ser.call(v)
160
+ else
161
+ result[k.to_s] = v
162
+ end
163
+ end
164
+ end
165
+ end
166
+ result
167
+ end
168
+ end
169
+ end
170
+ end