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.
@@ -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 (2.11.3)
11
- rake (0.9.2.2)
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.1)
19
- minitest (= 2.11.3)
20
- rake (= 0.9.2.2)
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
- # vellam [![Build Status](https://secure.travis-ci.org/mkristian/babel.png)](http://travis-ci.org/mkristian/babel) #
1
+ # babel #
2
+
3
+ * [![Build Status](https://secure.travis-ci.org/mkristian/babel.png)](http://travis-ci.org/mkristian/babel)
4
+ * [![Dependency Status](https://gemnasium.com/mkristian/ixtlan-babel.png)](https://gemnasium.com/mkristian/ixtlan-babel)
5
+ * [![Code Climate](https://codeclimate.com/badge.png)](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.filter
12
- @filter ||= HashFilter.new
11
+ def self.config
12
+ @config ||= FilterConfig.new
13
13
  end
14
14
 
15
15
  def filter
16
- @filter ||= self.class.filter.dup
16
+ @filter ||= HashFilter.new
17
17
  end
18
18
 
19
19
  protected
20
20
 
21
21
  def self.default_context_key(default)
22
- filter.default_context_key(default)
22
+ config.default_context_key(default)
23
23
  end
24
24
 
25
25
  def self.add_context(key, options = {})
26
- filter[key] = options
26
+ config[key] = options
27
27
  end
28
28
 
29
29
  public
30
30
 
31
31
  def use(context_or_options)
32
- filter.use(context_or_options)
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.use(options) if options
38
- if root = filter.options[:root]
39
- if data.is_a? Array
40
- root = root.to_s
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
- if data.is_a? Array
47
- data.collect{ |d| @model_class.new(filter.filter(d)) }
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