ixtlan-babel 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ require 'ixtlan/babel/serializer'
2
+ class DataMapper::Validations::ValidationErrorsSerializer < Ixtlan::Babel::Serializer
3
+
4
+ def to_hash( o = nil)
5
+ @model_or_models.to_hash
6
+ end
7
+
8
+ end
@@ -0,0 +1,6 @@
1
+ class DataMapper::Validations::ValidationErrorsSerializer < Ixtlan::Babel::Serializer
2
+ def to_hash( o = nil)
3
+ @model_or_models.to_hash
4
+ end
5
+
6
+ end
@@ -18,6 +18,7 @@
18
18
  # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
20
  #
21
+ require 'ixtlan/babel/dm_validation_errors_serializer' if defined? DataMapper
21
22
  module Ixtlan
22
23
  module Babel
23
24
  class Factory
@@ -56,7 +57,7 @@ module Ixtlan
56
57
  def new_serializer( resource )
57
58
  if resource.respond_to?(:model)
58
59
  model = resource.model
59
- elsif resource.respond_to? :collect
60
+ elsif resource.respond_to?( :collect) && !resource.respond_to?( :to_hash)
60
61
  if resource.empty?
61
62
  return EmptyArraySerializer.new
62
63
  else
@@ -0,0 +1,95 @@
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
+ module Ixtlan
22
+ module Babel
23
+ class Factory
24
+
25
+ NANOSECONDS_IN_DAY = 86400*10**6
26
+
27
+ TIME_TO_S = Proc.new do |t|
28
+ t.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % t.usec) + t.strftime('%z')
29
+ end
30
+
31
+ DATE_TIME_TO_S = Proc.new do |dt|
32
+ dt.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % (dt.sec_fraction * NANOSECONDS_IN_DAY ) ) + dt.strftime('%z')
33
+ end
34
+
35
+ DEFAULT_MAP = {
36
+ 'DateTime' => DATE_TIME_TO_S,
37
+ 'ActiveSupport::TimeWithZone' => TIME_TO_S,
38
+ 'Time' => TIME_TO_S
39
+ }
40
+
41
+ class EmptyArraySerializer < Array
42
+ def use(arg)
43
+ self
44
+ end
45
+ end
46
+
47
+ def initialize(custom_serializers = {})
48
+ @map = DEFAULT_MAP.dup
49
+ @map.merge!(custom_serializers)
50
+ end
51
+
52
+ def add( clazz, &block )
53
+ @map[ clazz.to_s ] = block
54
+ end
55
+
56
+ def new_serializer( resource )
57
+ if resource.respond_to?(:model)
58
+ model = resource.model
59
+ elsif resource.respond_to?( :collect) && !resource.respond_to?( :to_hash)
60
+ if resource.empty?
61
+ return EmptyArraySerializer.new
62
+ else
63
+ p resource
64
+ p resource.class
65
+ r = resource.first
66
+ model = r.respond_to?( :model ) ? r.model : r.class
67
+ p model
68
+ end
69
+ else
70
+ model = resource.class
71
+ end
72
+ ser = const_retrieve( "#{model}Serializer" ).new( resource )
73
+ ser.add_custom_serializers( @map )
74
+ ser
75
+ end
76
+
77
+ def new( resource )
78
+ warn 'DEPRECATED use new_serializer instead'
79
+ new_serializer( resource )
80
+ end
81
+
82
+ def new_filter( clazz )
83
+ const_retrieve( "#{clazz}Filter" ).new( clazz )
84
+ end
85
+
86
+ def const_retrieve( const )
87
+ obj = Object
88
+ const.split(/::/).each do |part|
89
+ obj = obj.const_get( part )
90
+ end
91
+ obj
92
+ end
93
+ end
94
+ end
95
+ end
@@ -1,107 +1,58 @@
1
- require 'ixtlan/babel/config'
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'
2
22
  module Ixtlan
3
23
  module Babel
4
- class HashFilter
24
+ class HashFilter < AbstractFilter
5
25
 
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
26
+ def filter( data )
27
+ if data
28
+ filter_data( data,
29
+ Context.new( options ) )
47
30
  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
31
  end
69
32
 
70
33
  private
71
34
 
72
- def options_for( hash )
73
- @options || (hash.is_a?(Array) ? collection_options : single_options)
74
- end
75
-
76
35
  def filter_array( array, options )
77
36
  array.collect do |item|
78
37
  if item.is_a?( Array ) || item.is_a?( Hash )
79
38
  filter_data( item, options )
80
39
  else
81
- item
40
+ serialize( item )
82
41
  end
83
42
  end
84
43
  end
85
44
 
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 )
45
+ def filter_data( data, context )
95
46
  result = {}
96
47
  data.each do |k,v|
97
48
  k = k.to_s
98
49
  case v
99
50
  when Hash
100
- result[ k ] = filter_data( v, config[ k ] ) if config.include?( k )
51
+ result[ k ] = filter_data( v, context[ k ] ) if context.include?( k )
101
52
  when Array
102
- result[ k ] = filter_array( v, config[ k ] ) if config.include?( k )
53
+ result[ k ] = filter_array( v, context[ k ] ) if context.include?( k )
103
54
  else
104
- result[ k ] = serialize( v ) if config.allowed?( k )
55
+ result[ k ] = serialize( v ) if context.allowed?( k )
105
56
  end
106
57
  end
107
58
  result
@@ -1,166 +1,69 @@
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'
1
22
  module Ixtlan
2
23
  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
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 )
45
32
  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
33
  end
72
34
 
73
35
  private
74
36
 
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]}]
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)
86
41
  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)
42
+ serialize( i )
93
43
  end
44
+ end
45
+ end
94
46
 
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
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 )
118
51
  end
119
52
  end
120
- methods ||= []
53
+ end
54
+
55
+ def filter_data(model, data, context, &block)
56
+ setup_data(model, data, context)
57
+
121
58
  result = {}
122
59
  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
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 )
156
65
  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
66
+ result[ k ] = serialize( v ) if context.allowed?( k ) && ! v.respond_to?( :attributes )
164
67
  end
165
68
  end
166
69
  result
@@ -0,0 +1,160 @@
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 'multi_json'
22
+ require 'ixtlan/babel/hash_filter'
23
+ require 'ixtlan/babel/model_filter'
24
+ require 'ixtlan/babel/filter_config'
25
+ module Ixtlan
26
+ module Babel
27
+ class Serializer
28
+
29
+ def id
30
+ if @model_or_models.is_a? Array
31
+ super
32
+ else
33
+ @model_or_models.id
34
+ end
35
+ end
36
+
37
+ def initialize(model_or_models)
38
+ @model_or_models = model_or_models
39
+ end
40
+
41
+ def respond_to?(method)
42
+ @model_or_models.respond_to?(method)
43
+ end
44
+
45
+ def method_missing(method, *args, &block)
46
+ @model_or_models.send(method, *args, &block)
47
+ end
48
+
49
+ def add_custom_serializers(map)
50
+ filter.add_custom_serializers(map)
51
+ end
52
+
53
+ private
54
+
55
+ def self.config
56
+ @config ||= FilterConfig.new
57
+ end
58
+
59
+ def filter
60
+ @filter ||= @model_or_models.is_a?( Hash ) ? HashFilter.new : ModelFilter.new
61
+ end
62
+
63
+ protected
64
+
65
+ # for rails
66
+ def self.model(model = nil)
67
+ @model_class = model if model
68
+ @model_class ||= self.to_s.sub(/Serializer$/, '').constantize
69
+ end
70
+
71
+ # for rails
72
+ def self.model_name
73
+ model.model_name
74
+ end
75
+
76
+ def self.default_context_key(single = :single, collection = :collection)
77
+ config.default_context_key(single, collection)
78
+ end
79
+
80
+ def self.add_context(key, options = {})
81
+ config[key] = options
82
+ end
83
+
84
+ def self.root( root )
85
+ config.root = root
86
+ end
87
+
88
+ public
89
+
90
+ def use( context_or_options )
91
+ @context_or_options = context_or_options
92
+ self
93
+ end
94
+
95
+ def to_hash(options = nil)
96
+ setup_filter( options )
97
+ if collection?
98
+ @model_or_models.collect do |m|
99
+ filter_model( m )
100
+ end
101
+ else
102
+ filter_model( @model_or_models )
103
+ end
104
+ end
105
+
106
+ def to_json(options = nil)
107
+ to_hash(options).to_json
108
+ end
109
+
110
+ def setup_filter(options)
111
+ o = if collection?
112
+ self.class.config.collection_options( @context_or_options )
113
+ else
114
+ self.class.config.single_options( @context_or_options )
115
+ end
116
+ filter.options = o.merge!( options || {} )
117
+ filter.options[:root] ||= self.class.config.root
118
+ end
119
+ private :setup_filter
120
+
121
+ def collection?
122
+ @is_collection ||= @model_or_models.respond_to?(:collect) && ! @model_or_models.is_a?(Hash)
123
+ end
124
+ private :collection?
125
+
126
+ def to_xml(options = nil)
127
+ setup_filter
128
+
129
+ result = to_hash
130
+
131
+ root = config.root
132
+
133
+ if root && result.is_a?(Array) && root.respond_to?(:pluralize)
134
+ root = root.pluralize
135
+ end
136
+ result.to_xml :root => root
137
+ end
138
+
139
+ def to_yaml(options = nil)
140
+ to_hash(options).to_yaml
141
+ end
142
+
143
+ protected
144
+
145
+ def attr(model)
146
+ model.attributes if model
147
+ end
148
+
149
+ private
150
+
151
+ def filter_model( model )
152
+ if root = filter.options[:root]
153
+ { root.to_s => filter.filter( model ){ |model| attr(model) } }
154
+ else
155
+ filter.filter( model ){ |model| attr(model) }
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: ixtlan-babel
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.3
5
+ version: 0.3.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Christian Meier
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-28 00:00:00.000000000 Z
12
+ date: 2013-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -117,6 +117,7 @@ files:
117
117
  - lib/ixtlan-babel.rb
118
118
  - lib/ixtlan/babel/deserializer.rb
119
119
  - lib/ixtlan/babel/hash_filter.rb
120
+ - lib/ixtlan/babel/serializer.rb~
120
121
  - lib/ixtlan/babel/params_filter.rb
121
122
  - lib/ixtlan/babel/abstract_filter.rb
122
123
  - lib/ixtlan/babel/no_timestamp_serializer.rb
@@ -125,9 +126,12 @@ files:
125
126
  - lib/ixtlan/babel/context.rb
126
127
  - lib/ixtlan/babel/factory.rb
127
128
  - lib/ixtlan/babel/model_filter.rb~
129
+ - lib/ixtlan/babel/dm_validation_errors_serializer.rb
128
130
  - lib/ixtlan/babel/hash_filter.rb~
129
131
  - lib/ixtlan/babel/filter_config.rb~
130
132
  - lib/ixtlan/babel/hash_only_filter.rb~
133
+ - lib/ixtlan/babel/factory.rb~
134
+ - lib/ixtlan/babel/dm_validation_errors_serializer.rb~
131
135
  - lib/ixtlan/babel/context.rb~
132
136
  - lib/ixtlan/babel/model_filter.rb
133
137
  - lib/ixtlan/babel/hash_filter.rb-