ixtlan-babel 0.5.0 → 0.7.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.
@@ -1,62 +1,171 @@
1
- #
2
- # Copyright (C) 2013 Christian Meier
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
- # this software and associated documentation files (the "Software"), to deal in
6
- # the Software without restriction, including without limitation the rights to
7
- # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
- # the Software, and to permit persons to whom the Software is furnished to do so,
9
- # subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
- # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
- # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
- # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
- #
21
- require 'ixtlan/babel/abstract_filter'
22
1
  module Ixtlan
23
2
  module Babel
24
- class HashFilter < AbstractFilter
3
+
4
+ module HashFilter
5
+
6
+ def self.included( model )
7
+ model.extend( ClassMethods )
8
+ end
25
9
 
26
10
  def filter( data )
27
- if data
28
- filter_data( data,
29
- Context.new( options ) )
11
+ @attributes = do_filter( data, self.class.attributes )
12
+ end
13
+
14
+ def hidden( data )
15
+ @hidden = do_filter( data, self.class.hiddens )
16
+ end
17
+
18
+ def attributes
19
+ @attributes
20
+ end
21
+ alias :params :attributes
22
+
23
+ def new_model
24
+ if @class
25
+ @class.new( @attributes )
30
26
  end
31
27
  end
32
28
 
33
- private
29
+ def respond_to? name
30
+ key = name.to_sym
31
+ self.class.hiddens.key?( key ) || self.class.attributes.key?( key ) || super
32
+ end
34
33
 
35
- def filter_array( array, options )
36
- array.collect do |item|
37
- if item.is_a?( Array ) || item.is_a?( Hash )
38
- filter_data( item, options )
34
+ def method_missing( name, *args )
35
+ key = name.to_sym
36
+ if self.class.hiddens.key?( key )
37
+ to_attribute( key,
38
+ @hidden[ key ] || @hidden[ key.to_s ],
39
+ self.class.hiddens )
40
+ elsif self.class.attributes.key?( key )
41
+ to_attribute( key,
42
+ @attributes[ key ] || @attributes[ key.to_s ],
43
+ self.class.attributes )
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def to_attribute( key, v, ref )
50
+ case v
51
+ when Hash
52
+ ref[ key ].replace( v )
53
+ else
54
+ v
55
+ end
56
+ end
57
+
58
+ def do_filter( data, ref )
59
+ data.reject do |k,v|
60
+ case v
61
+ when Hash
62
+ if babel = ref[ k.to_sym ]
63
+ v.replace babel.replace( v ).attributes
64
+ false
65
+ else
66
+ true
67
+ end
68
+ when ::Array
69
+ if babel = ref[ k.to_sym ]
70
+ v.each do |vv|
71
+ vv.replace babel.replace( vv ).attributes
72
+ end
73
+ false
74
+ else
75
+ true
76
+ end
39
77
  else
40
- serialize( item )
78
+ not ref.member?( k.to_sym )
41
79
  end
42
80
  end
43
81
  end
82
+
83
+ def initialize( clazz = nil )
84
+ super()
85
+ replace( {} )
86
+ @class = clazz
87
+ end
88
+
89
+ def replace( data )
90
+ data = deep_dup( data )
91
+ filter( data )
92
+ hidden( data )
93
+ self
94
+ end
95
+
96
+ private
44
97
 
45
- def filter_data( data, context )
46
- result = {}
98
+ def deep_dup( data )
99
+ data = data.dup
47
100
  data.each do |k,v|
48
- k = k.to_s
49
- case v
50
- when Hash
51
- result[ k ] = filter_data( v, context[ k ] ) if context.include?( k )
101
+ if v.is_a? Hash
102
+ data[ k ] = deep_dup( v )
103
+ end
104
+ end
105
+ end
106
+
107
+ module ClassMethods
108
+
109
+ def attribute( name, type = nil )
110
+ attributes[ name.to_sym ] = new_instance( type )
111
+ end
112
+
113
+ def hidden( name, type = nil )
114
+ hiddens[ name.to_sym ] = new_instance( type )
115
+ end
116
+
117
+ def attributes( *args )
118
+ if args.size == 0
119
+ @attributes ||= (superclass.attributes.dup rescue nil) || {}
120
+ else
121
+ args.each { |a| attribute( a ) }
122
+ end
123
+ end
124
+
125
+ def hiddens( *args )
126
+ if args.size == 0
127
+ @hiddens ||= (superclass.hiddens.dup rescue nil) || {}
128
+ else
129
+ args.each { |a| hidden( a ) }
130
+ end
131
+ end
132
+
133
+ def new_instance( type )
134
+ case type
52
135
  when Array
53
- result[ k ] = filter_array( v, context[ k ] ) if context.include?( k )
136
+ type[ 0 ].new
137
+ when NilClass
138
+ nil
54
139
  else
55
- result[ k ] = serialize( v ) if context.allowed?( k )
140
+ type.new
56
141
  end
57
142
  end
58
- result
59
143
  end
60
144
  end
61
145
  end
62
146
  end
147
+ # class ModifiedBy
148
+ # include Babel::HashFilter
149
+
150
+ # attribute :id
151
+ # end
152
+ # User = ModifiedBy
153
+
154
+ # class A
155
+ # include Babel::HashFilter
156
+
157
+ # attribute :id
158
+ # attribute :created_at, Array[User]
159
+ # hidden :updated_at
160
+ # attribute :modified_by, ModifiedBy
161
+
162
+ # end
163
+
164
+ # data = {:a=>123, :id => 432, :created_at => [ {:id => 12, :name => 'asd' } ], :updated_at => 'asd', :modified_by => { :id => 342 } }
165
+ # a = A.new.replace(data )
166
+ # p a.attributes
167
+ # p a
168
+ # p a.updated_at
169
+ # p a.id
170
+ # p a.modified_by
171
+ # p a.modified_by.id
@@ -1,73 +1,135 @@
1
- #
2
- # Copyright (C) 2013 Christian Meier
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
- # this software and associated documentation files (the "Software"), to deal in
6
- # the Software without restriction, including without limitation the rights to
7
- # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
- # the Software, and to permit persons to whom the Software is furnished to do so,
9
- # subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
- # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
- # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
- # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
- #
21
- require 'ixtlan/babel/abstract_filter'
22
1
  module Ixtlan
23
2
  module Babel
24
- class ModelFilter < AbstractFilter
25
-
26
- def filter( model, &block )
27
- if model
28
- data = block.call( model )
29
- filter_data( model, data,
30
- Context.new( options ),
31
- &block )
32
- end
3
+
4
+ module ModelFilter
5
+
6
+ def self.included( model )
7
+ model.extend( ClassMethods )
33
8
  end
34
9
 
35
- private
10
+ def respond_to? name
11
+ @model.respond_to? name
12
+ end
36
13
 
37
- def filter_array( models, options, &block )
38
- models.collect do |i|
39
- if i.respond_to? :attributes
40
- filter_data(i, block.call(i), options, &block)
41
- else
42
- serialize( i )
14
+ def method_missing( name, *args, &block )
15
+ @model.send( name, *args, &block )
16
+ end
17
+
18
+ def to_json
19
+ to_data.to_json
20
+ end
21
+
22
+ def to_yaml
23
+ to_data.to_yaml
24
+ end
25
+
26
+ def to_data
27
+ case @model
28
+ when Array
29
+ @model.collect do |m|
30
+ replace( m ).to_hash
43
31
  end
32
+ else
33
+ to_hash
44
34
  end
45
35
  end
46
36
 
47
- def setup_data(model, data, context)
48
- context.methods.each do |m|
49
- unless data.include?(m)
50
- data[ m ] = model.send( m.to_sym )
51
- end
37
+ def serializers=( map )
38
+ @map = map
39
+ end
40
+
41
+ def serialize( data )
42
+ if @map && ser = @map[ data.class.to_s ]
43
+ ser.call( data )
44
+ else
45
+ data
52
46
  end
53
47
  end
54
48
 
55
- def filter_data(model, data, context, &block)
56
- setup_data(model, data, context)
57
-
49
+ def to_hash
58
50
  result = {}
59
- data.each do |k,v|
60
- k = k.to_s
61
- if v.respond_to? :attributes
62
- result[ k ] = filter_data( v, block.call(v), context[ k ], &block ) if context.include?( k )
63
- elsif v.is_a? Array
64
- result[ k ] = filter_array( v, context[ k ], &block ) if context.include?( k )
51
+ self.class.attributes.each do |k,v|
52
+ if v
53
+ filter = v.is_a?( Array ) ? v[ 0 ] : v
54
+ filter.serializers = @map
55
+ model = @model.send( k )
56
+ result[ k ] = filter.replace( model ).to_data if model
65
57
  else
66
- result[ k ] = serialize( v ) if context.allowed?( k ) && ! v.respond_to?( :attributes )
58
+ result[ k ] = serialize( @model.send( k ) )
67
59
  end
68
60
  end
69
61
  result
70
62
  end
63
+
64
+ def initialize( model = nil, map = nil )
65
+ super()
66
+ @map = map
67
+ replace( model )
68
+ end
69
+
70
+ def replace( model )
71
+ @model = model
72
+ self
73
+ end
74
+
75
+ module ClassMethods
76
+
77
+ def attribute( name, type = nil )
78
+ attributes[ name.to_sym ] = new_instance( type )
79
+ end
80
+
81
+ def attributes
82
+ @attributes ||= (superclass.attributes.dup rescue nil) || {}
83
+ end
84
+
85
+ def new_instance( type )
86
+ case type
87
+ when Array
88
+ [ type[ 0 ].new ]
89
+ when NilClass
90
+ nil
91
+ else
92
+ type.new
93
+ end
94
+ end
95
+ end
71
96
  end
72
97
  end
73
98
  end
99
+
100
+ # class User
101
+ # include Babel::ModelFilter
102
+
103
+ # attribute :id
104
+ # end
105
+ # class A
106
+ # include Babel::ModelFilter
107
+
108
+ # attribute :id
109
+ # attribute :created_at, Array[User]
110
+ # attribute :updated_at
111
+ # attribute :modified_by, User
112
+
113
+ # end
114
+
115
+ # class B
116
+ # attr_accessor :id, :created_at, :updated_at, :name, :modified_by
117
+ # end
118
+
119
+ # b = B.new
120
+ # b.id = 123
121
+ # require 'date'
122
+ # b.updated_at = DateTime.now
123
+ # b.name ='bla'
124
+ # b.modified_by = B.new
125
+ # b.modified_by.id = 432
126
+ # b.modified_by.name = 'asd432'
127
+ # b.created_at = [ b, b.modified_by]
128
+
129
+ # require_relative 'factory'
130
+ # a = A.new( b, Babel::Factory::DEFAULT_MAP )
131
+
132
+ # p a
133
+ # p a.to_hash
134
+
135
+ # p a.id
@@ -0,0 +1,103 @@
1
+ module Ixtlan
2
+ module Babel
3
+
4
+ module ModelSerializer
5
+
6
+ attr_reader :model
7
+
8
+ def self.included( model )
9
+ model.extend( ClassMethods )
10
+ end
11
+
12
+ def respond_to? name
13
+ @model.respond_to? name
14
+ end
15
+
16
+ def method_missing( name, *args, &block )
17
+ @model.send( name, *args, &block )
18
+ end
19
+
20
+ def to_json
21
+ to_data.to_json
22
+ end
23
+
24
+ def to_yaml
25
+ to_data.to_yaml
26
+ end
27
+
28
+ def to_data
29
+ if @model.respond_to?( :collect ) and not @model.is_a?( Hash )
30
+ @model.collect do |m|
31
+ replace( m ).to_hash
32
+ end
33
+ else
34
+ to_hash
35
+ end
36
+ end
37
+
38
+ def serializers=( map )
39
+ @map = map
40
+ end
41
+
42
+ def serialize( data )
43
+ if @map && ser = @map[ data.class.to_s ]
44
+ ser.call(data)
45
+ else
46
+ data
47
+ end
48
+ end
49
+
50
+ def to_hash
51
+ result = {}
52
+ self.class.attributes.each do |k,v|
53
+ if v
54
+ filter = v.is_a?( Array ) ? v[ 0 ] : v
55
+ filter.serializers = @map
56
+ model = @model.send( k )
57
+ result[ k ] = filter.replace( model ).to_data if model
58
+ else
59
+ result[ k ] = serialize( @model.send( k ) )
60
+ end
61
+ end
62
+ result
63
+ end
64
+
65
+ def initialize( model = nil, map = nil )
66
+ super()
67
+ @map = map
68
+ replace( model )
69
+ end
70
+
71
+ def replace( model )
72
+ @model = model
73
+ self
74
+ end
75
+
76
+ module ClassMethods
77
+
78
+ def attribute( name, type = nil )
79
+ attributes[ name.to_sym ] = new_instance( type )
80
+ end
81
+
82
+ def attributes( *args )
83
+ if args.size == 0
84
+ @attributes ||= (superclass.attributes.dup rescue nil) || {}
85
+ else
86
+ args.each { |a| attribute( a ) }
87
+ end
88
+ end
89
+
90
+ def new_instance( type )
91
+ case type
92
+ when Array
93
+ [ type[ 0 ].new ]
94
+ when NilClass
95
+ nil
96
+ else
97
+ type.new
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end