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.
@@ -2,6 +2,22 @@ module Ixtlan
2
2
  module Babel
3
3
  class Factory
4
4
 
5
+ NANOSECONDS_IN_DAY = Rational(1, 86400*10**9)
6
+
7
+ TIME_TO_S = Proc.new do |t|
8
+ t.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % t.usec) + t.strftime('%z')
9
+ end
10
+
11
+ DATE_TIME_TO_S = Proc.new do |dt|
12
+ dt.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % (dt.sec_fraction / NANOSECONDS_IN_DAY / 1000)) + dt.strftime('%z')
13
+ end
14
+
15
+ DEFAULT_MAP = {
16
+ 'DateTime' => DATE_TIME_TO_S,
17
+ 'ActiveSupport::TimeWithZone' => TIME_TO_S,
18
+ 'Time' => TIME_TO_S
19
+ }
20
+
5
21
  class EmptyArraySerializer < Array
6
22
  def use(arg)
7
23
  self
@@ -9,16 +25,7 @@ module Ixtlan
9
25
  end
10
26
 
11
27
  def initialize(custom_serializers = {})
12
- @map = {}
13
- add('DateTime') do |dt|
14
- dt.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % (dt.sec_fraction / Date::NANOSECONDS_IN_DAY / 1000)) + dt.strftime('%z')
15
- end
16
- add('ActiveSupport::TimeWithZone') do |tz|
17
- tz.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % tz.usec) + tz.strftime('%z')
18
- end
19
- add('Time') do |t|
20
- t.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % t.usec) + t.strftime('%z')
21
- end
28
+ @map = DEFAULT_MAP.dup
22
29
  @map.merge!(custom_serializers)
23
30
  end
24
31
 
@@ -29,7 +36,7 @@ module Ixtlan
29
36
  def new(resource)
30
37
  if resource.respond_to?(:model)
31
38
  model = resource.model
32
- elsif resource.is_a? Array
39
+ elsif resource.respond_to? :collect
33
40
  if resource.empty?
34
41
  return EmptyArraySerializer.new
35
42
  else
@@ -39,10 +46,18 @@ module Ixtlan
39
46
  else
40
47
  model = resource.class
41
48
  end
42
- ser = Object.const_get("#{model}Serializer").new(resource)
49
+ ser = const_retrieve("#{model}Serializer").new(resource)
43
50
  ser.add_custom_serializers(@map)
44
51
  ser
45
52
  end
53
+
54
+ def const_retrieve( const )
55
+ obj = Object
56
+ const.split(/::/).each do |part|
57
+ obj = obj.const_get( part )
58
+ end
59
+ obj
60
+ end
46
61
  end
47
62
  end
48
63
  end
@@ -0,0 +1,52 @@
1
+ require 'ixtlan/babel/context'
2
+ module Ixtlan
3
+ module Babel
4
+ class FilterConfig
5
+
6
+ private
7
+
8
+ def context
9
+ @context ||= {}
10
+ end
11
+
12
+ def context_options( context_or_options )
13
+ if context_or_options
14
+ case context_or_options
15
+ when Symbol
16
+ if opts = context[ context_or_options ]
17
+ opts.dup
18
+ end
19
+ when Hash
20
+ context_or_options
21
+ end
22
+ end
23
+ end
24
+
25
+ public
26
+
27
+ def default_context_key( single = :single,
28
+ collection = :collection )
29
+ @single, @collection = single, collection
30
+ end
31
+
32
+ def []=( key, options )
33
+ context[ key.to_sym ] = options if key
34
+ end
35
+
36
+ def []( key )
37
+ context[ key.to_sym ] if key
38
+ end
39
+
40
+ def single_options( context_or_options )
41
+ context_options( context_or_options ) || context[default_context_key[0]] || {}
42
+ end
43
+
44
+ def collection_options( context_or_options )
45
+ context_options( context_or_options ) || context[default_context_key[1]] || {}
46
+ end
47
+
48
+ attr_accessor :root
49
+
50
+ end
51
+ end
52
+ 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( hash = {} )
52
+ if hash
53
+ filter_data( hash,
54
+ Context.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, 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
@@ -1,144 +1,38 @@
1
+ require 'ixtlan/babel/abstract_filter'
1
2
  module Ixtlan
2
3
  module Babel
3
- class HashFilter
4
+ class HashFilter < AbstractFilter
4
5
 
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(default = nil)
22
- @default = default if default
23
- @default
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
6
+ def filter( data )
7
+ if data
8
+ filter_data( data,
9
+ Context.new( options ) )
46
10
  end
47
- self
48
- end
49
-
50
- NO_MODEL = Object.new
51
- def NO_MODEL.send(*args)
52
- self
53
- end
54
- def NO_MODEL.[](*args)
55
- self
56
- end
57
-
58
- def filter(hash = {}, model = NO_MODEL, &block)
59
- filter_data(model, hash, options, &block) if hash
60
- end
61
-
62
- def options
63
- @options || context[default_context_key] || {}
64
11
  end
65
12
 
66
13
  private
67
14
 
68
- def filter_data(model, data, options = {}, &block)
69
- model = NO_MODEL if model == data
70
- only = options[:only].collect { |o| o.to_s } if options[:only]
71
- except = (options[:except] || []).collect { |e| e.to_s }
72
-
73
- include =
74
- case options[:include]
75
- when Array
76
- options[:include].collect { |i| i.to_s }
77
- when Hash
78
- Hash[options[:include].collect {|k,v| [k.to_s, v]}]
15
+ def filter_array( array, options )
16
+ array.collect do |item|
17
+ if item.is_a?( Array ) || item.is_a?( Hash )
18
+ filter_data( item, options )
79
19
  else
80
- []
81
- end
82
- if model != NO_MODEL
83
- methods = (options[:methods] || []).collect { |e| e.to_s }
84
- methods.each do |m|
85
- data[m] = model.send(m.to_sym)
86
- end
87
-
88
- include_methods = include.is_a?(Array) ? include : include.keys
89
- include_methods.each do |m|
90
- unless data.include?(m)
91
- raise "no block given to calculate the attributes from model" unless block
92
- models_or_model = model.send(m)
93
- if models_or_model.respond_to?(:collect)
94
- data[m] = models_or_model.collect { |i| block.call(i) }
95
- else
96
- data[m]= block.call(model.send(m))
97
- end
98
- end
20
+ item
99
21
  end
100
22
  end
101
- methods ||= []
23
+ end
102
24
 
25
+ def filter_data( data, context )
103
26
  result = {}
104
27
  data.each do |k,v|
28
+ k = k.to_s
105
29
  case v
106
30
  when Hash
107
- if include.include?(k.to_s)
108
- case include
109
- when Array
110
- result[k.to_s] = filter_data(model.send(k), v, &block)
111
- when Hash
112
- result[k.to_s] = filter_data(model.send(k), v, include[k.to_s], &block)
113
- end
114
- end
31
+ result[ k ] = filter_data( v, context[ k ] ) if context.include?( k )
115
32
  when Array
116
- if include.include?(k.to_s)
117
- models = model.send(k)
118
- j = -1
119
- case include
120
- when Array
121
- result[k.to_s] = v.collect do |i|
122
- j += 1
123
- if i.is_a?(Array) || i.is_a?(Hash)
124
- filter_data(models[j], i, &block)
125
- else
126
- i
127
- end
128
- end
129
- when Hash
130
- opts = include[k]
131
- result[k.to_s] = v.collect { |i| j += 1; filter_data(models[j], i, opts, &block) }
132
- end
133
- end
33
+ result[ k ] = filter_array( v, context[ k ] ) if context.include?( k )
134
34
  else
135
- if methods.include?(k.to_s) || (only && only.include?(k.to_s)) || (only.nil? && !except.include?(k.to_s))
136
- if @map && ser = @map[v.class.to_s]
137
- result[k.to_s] = ser.call(v)
138
- else
139
- result[k.to_s] = v
140
- end
141
- end
35
+ result[ k ] = serialize( v ) if context.allowed?( k )
142
36
  end
143
37
  end
144
38
  result
@@ -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