ixtlan-babel 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f025bd8665c42f07f792f3fb8a28331a62e47274
4
- data.tar.gz: 4c3df0b63c0574acc37ec06cd33e9f18e0c1c809
3
+ metadata.gz: 00259cfa886327c377f73044439ec871fcb05e05
4
+ data.tar.gz: b4e094454585371ad6d79e9787b920691af6b796
5
5
  SHA512:
6
- metadata.gz: 8b5267f3135e38b8053da3d39a30a87093ccd11f0c9e2837c3264b346dffd96613a17031f3d6ef5e98a34657652475452f12c96bcdcc81484f21021f01ce2dec
7
- data.tar.gz: f1be049f637b3dd246fb4f8353f71662e3e3bfd8fe806d3514c82b74f80e839723ed9345b4d5e2cce38c6d290397d2f9eaf59bd36b7bfcff3d61b2bc6713a494
6
+ metadata.gz: df6693a953826957ce9d074f076c2a0f1072fac6e2816a73b132b4962ad6d8d3c9cf0aa3fe3510b94424fed0b93415dfcde9a3901d18f2a7da581e97ee29648f
7
+ data.tar.gz: b05cff1c83d9be2acefdb1bac1860e861a46753fbcd57660e9854e5c3f66800af6b007633709663eab25f1aba2c6ef1bdef24891b1b38038fcc0a9613546047e
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
+ # -*- mode: ruby -*-
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
5
- gem 'copyright-header', '~> 1.0', :platform => :mri, :group => :copyright
7
+ gem 'copyright-header', '~>1.0', :platform => :mri, :group => :copyright
6
8
 
9
+ # vim: syntax=Ruby
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Kristian Meier
1
+ Copyright (c) 2008 Kristian Meier
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,19 +1,9 @@
1
- # babel #
1
+ # Ixtlan Babel #
2
2
 
3
- * [![Build Status](https://secure.travis-ci.org/mkristian/babel.png)](http://travis-ci.org/mkristian/babel)
3
+ * [![Build Status](https://secure.travis-ci.org/mkristian/ixtlan-babel.png)](http://travis-ci.org/mkristian/ixtlan-babel)
4
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)
5
+ * [![Code Climate](https://codeclimate.com/github/mkristian/ixtlan-babel.png)](https://codeclimate.com/github/mkristian/ixtlan-babel)
6
6
 
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.
8
-
9
- the first problem I had was that I needed serveral options map at different controllers/actions so I needed a place to store them. the model itself felt to be the wrong place.
10
-
11
- the next problem was that I could include the result of a given method with `:methods => ['age']` but only on the root level of the object tree. but if I wanted to `age` method to be part of the serialization somewhere deep inside the object tree, it is not possible.
12
-
13
- please have a look at **spec/filter_spec.rb** how to use it :)
14
-
15
- TODO usage
16
- ==========
17
7
 
18
8
  Contributing
19
9
  ------------
@@ -28,4 +18,3 @@ meta-fu
28
18
  -------
29
19
 
30
20
  enjoy :)
31
-
@@ -0,0 +1,27 @@
1
+ # -*- mode: ruby -*-
2
+
3
+ task :default => [ :spec ]
4
+
5
+ task :spec do
6
+ Dir['spec/*_spec.rb'].each { |f| require File.expand_path( f ) }
7
+ end
8
+
9
+ task :headers do
10
+ require 'copyright_header'
11
+
12
+ s = Gem::Specification.load( Dir["*gemspec"].first )
13
+
14
+ args = {
15
+ :license => s.license,
16
+ :copyright_software => s.name,
17
+ :copyright_software_description => s.description,
18
+ :copyright_holders => s.authors,
19
+ :copyright_years => [Time.now.year],
20
+ :add_path => 'lib',
21
+ :output_dir => './'
22
+ }
23
+
24
+ command_line = CopyrightHeader::CommandLine.new( args )
25
+ command_line.execute
26
+ end
27
+ # vim: syntax=Ruby
@@ -1,22 +1 @@
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/serializer'
22
1
  require 'ixtlan/babel/factory'
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,21 @@
1
+ require 'ixtlan/babel/hash_filter'
2
+ require 'ixtlan/babel/model_serializer'
3
+
4
+ class Ixtlan::Babel::IdFilter
5
+ include Ixtlan::Babel::HashFilter
6
+
7
+ attributes :id
8
+ end
9
+
10
+ class Ixtlan::Babel::UpdatedAtFilter
11
+ include Ixtlan::Babel::HashFilter
12
+
13
+ hidden :updated_at
14
+ end
15
+
16
+ class Ixtlan::Babel::CollectionSerializer
17
+ include Ixtlan::Babel::ModelSerializer
18
+
19
+ attributes :offset, :total_count
20
+ end
21
+
@@ -0,0 +1,14 @@
1
+ require 'ixtlan/babel/hash_filter'
2
+
3
+ class Ixtlan::Babel::IdFilter
4
+ include Ixtlan::Babel::HashFilter
5
+
6
+ attributes :id
7
+ end
8
+
9
+ class Ixtlan::Babel::UpdatedAtFilter
10
+ include Ixtlan::Babel::HashFilter
11
+
12
+ hidden :updated_at
13
+ end
14
+
@@ -1,26 +1,8 @@
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/dm_validation_errors_serializer' if defined? DataMapper
1
+ require 'ixtlan/babel/hash_filter'
2
+ require 'ixtlan/babel/model_serializer'
22
3
  module Ixtlan
23
4
  module Babel
5
+
24
6
  class Factory
25
7
 
26
8
  NANOSECONDS_IN_DAY = 86400*10**6
@@ -33,61 +15,59 @@ module Ixtlan
33
15
  dt.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % (dt.sec_fraction * NANOSECONDS_IN_DAY ) )[0..6] + dt.strftime('%z')
34
16
  end
35
17
 
18
+ DATE_TO_S = Proc.new do |d|
19
+ d.strftime('%Y-%m-%d' )
20
+ end
21
+
36
22
  DEFAULT_MAP = {
37
23
  'DateTime' => DATE_TIME_TO_S,
24
+ 'Date' => DATE_TO_S,
38
25
  'ActiveSupport::TimeWithZone' => TIME_TO_S,
39
26
  'Time' => TIME_TO_S
40
27
  }
41
28
 
42
- class EmptyArraySerializer < Array
43
- def use(arg)
44
- self
45
- end
46
- end
47
-
48
- def initialize(custom_serializers = {})
29
+ def initialize( custom_serializers = {} )
49
30
  @map = DEFAULT_MAP.dup
50
- @map.merge!(custom_serializers)
31
+ @map.merge!( custom_serializers )
51
32
  end
52
33
 
53
- def add( clazz, &block )
54
- @map[ clazz.to_s ] = block
34
+ def serializer( resource, context = nil )
35
+ if model = to_model( resource )
36
+ clazz = '::' + model.to_s
37
+ to_class( clazz, 'Serializer', context ).new( resource, @map )
38
+ else
39
+ []
40
+ end
55
41
  end
56
42
 
57
- def new_serializer( resource )
43
+ private
44
+ def to_model( resource )
58
45
  if resource.respond_to?(:model)
59
- model = resource.model
60
- elsif resource.respond_to?( :collect) &&
61
- !resource.respond_to?( :to_hash)
46
+ resource.model
47
+ elsif( resource.respond_to?( :collect ) &&
48
+ !resource.respond_to?( :to_hash ) )
62
49
  if resource.empty?
63
- return EmptyArraySerializer.new
50
+ nil
64
51
  else
65
- r = resource.first
66
- model = r.respond_to?( :model ) ? r.model : r.class
52
+ to_model( resource.first )
67
53
  end
68
54
  else
69
- model = resource.class
55
+ resource.class
70
56
  end
71
- ser = const_retrieve( "#{model}Serializer" ).new( resource )
72
- ser.add_custom_serializers( @map )
73
- ser
74
57
  end
75
58
 
76
- def new( resource )
77
- warn 'DEPRECATED use new_serializer instead'
78
- new_serializer( resource )
79
- end
80
-
81
- def new_filter( clazz )
82
- const_retrieve( "#{clazz}Filter" ).new( clazz )
83
- end
84
-
85
- def const_retrieve( const )
86
- obj = Object
87
- const.split(/::/).each do |part|
88
- obj = obj.const_get( part )
59
+ def to_class( clazz, postfix, context )
60
+ if context.is_a? Class
61
+ context
62
+ else
63
+ context = context.to_s.split( /_/ ).collect { |s| s.capitalize }.join
64
+ c = clazz.to_s.sub( /^::/, '' ).sub( /(::)?([a-zA-Z0-9]+)$/, "\\1#{context}\\2#{postfix}" )
65
+ obj = Object
66
+ c.split( /::/ ).each do |part|
67
+ obj = obj.const_get( part )
68
+ end
69
+ obj
89
70
  end
90
- obj
91
71
  end
92
72
  end
93
73
  end
@@ -1,25 +1,8 @@
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
- #
1
+ require 'ixtlan/babel/hash_filter'
2
+ require 'ixtlan/babel/model_serializer'
21
3
  module Ixtlan
22
4
  module Babel
5
+
23
6
  class Factory
24
7
 
25
8
  NANOSECONDS_IN_DAY = 86400*10**6
@@ -29,67 +12,64 @@ module Ixtlan
29
12
  end
30
13
 
31
14
  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')
15
+ dt.strftime('%Y-%m-%dT%H:%M:%S.') + ("%06d" % (dt.sec_fraction * NANOSECONDS_IN_DAY ) )[0..6] + dt.strftime('%z')
33
16
  end
34
-
17
+
18
+ DATE_TO_S = Proc.new do |d|
19
+ d.strftime('%Y-%m-%d' )
20
+ end
21
+
35
22
  DEFAULT_MAP = {
36
23
  'DateTime' => DATE_TIME_TO_S,
24
+ 'Date' => DATE_TO_S,
37
25
  'ActiveSupport::TimeWithZone' => TIME_TO_S,
38
26
  'Time' => TIME_TO_S
39
27
  }
40
28
 
41
- class EmptyArraySerializer < Array
42
- def use(arg)
43
- self
44
- end
45
- end
46
-
47
- def initialize(custom_serializers = {})
29
+ def initialize( custom_serializers = {} )
48
30
  @map = DEFAULT_MAP.dup
49
- @map.merge!(custom_serializers)
31
+ @map.merge!( custom_serializers )
50
32
  end
51
33
 
52
- def add( clazz, &block )
53
- @map[ clazz.to_s ] = block
34
+ def serializer( resource, context = nil )
35
+ if model = to_model( resource )
36
+ clazz = '::' + model.to_s
37
+ to_class( clazz, 'Serializer', context ).new( resource, @map )
38
+ else
39
+ []
40
+ end
54
41
  end
55
42
 
56
- def new_serializer( resource )
43
+ private
44
+ def to_model( resource )
57
45
  if resource.respond_to?(:model)
58
- model = resource.model
59
- elsif resource.respond_to?( :collect) && !resource.respond_to?( :to_hash)
46
+ resource.model
47
+ elsif( resource.respond_to?( :collect ) &&
48
+ !resource.respond_to?( :to_hash ) )
60
49
  if resource.empty?
61
- return EmptyArraySerializer.new
50
+ nil
62
51
  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
52
+ to_model( resource.first )
68
53
  end
69
54
  else
70
- model = resource.class
55
+ resource.class
71
56
  end
72
- ser = const_retrieve( "#{model}Serializer" ).new( resource )
73
- ser.add_custom_serializers( @map )
74
- ser
75
57
  end
76
58
 
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 )
59
+ def to_class( clazz, postfix, context )
60
+ if context.is_a? Class
61
+ context
62
+ else
63
+ context = context.to_s.split( /_/ ).collect { |s| s.capitalize }.join
64
+ c = clazz.to_s.sub( /^::/, '' ).sub( /(::)?([a-zA-Z0-9]+)$/, "\\1#{context}\\2#{postfix}" )
65
+ obj = Object
66
+ c.split( /::/ ).each do |part|
67
+ obj = obj.const_get( part )
68
+ end
69
+ obj
90
70
  end
91
- obj
92
71
  end
93
72
  end
73
+
94
74
  end
95
75
  end
@@ -1,65 +1,146 @@
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 respond_to? name
24
+ key = name.to_sym
25
+ self.class.hiddens.key?( key ) || self.class.attributes.key?( key ) || super
26
+ end
27
+
28
+ def method_missing( name, *args )
29
+ key = name.to_sym
30
+ if self.class.hiddens.key?( key )
31
+ to_attribute( key,
32
+ @hidden[ key ] || @hidden[ key.to_s ],
33
+ self.class.hiddens )
34
+ elsif self.class.attributes.key?( key )
35
+ to_attribute( key,
36
+ @attributes[ key ] || @attributes[ key.to_s ],
37
+ self.class.attributes )
38
+ else
39
+ super
30
40
  end
31
41
  end
32
42
 
33
- private
43
+ def to_attribute( key, v, ref )
44
+ case v
45
+ when Hash
46
+ ref[ key ].replace( v )
47
+ else
48
+ v
49
+ end
50
+ end
34
51
 
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 )
52
+ def do_filter( data, ref )
53
+ data.reject do |k,v|
54
+ case v
55
+ when Hash
56
+ if babel = ref[ k.to_sym ]
57
+ v.replace babel.replace( v ).attributes
58
+ false
59
+ else
60
+ true
61
+ end
62
+ when ::Array
63
+ if babel = ref[ k.to_sym ]
64
+ v.each do |vv|
65
+ vv.replace babel.replace( vv ).attributes
66
+ end
67
+ false
68
+ else
69
+ true
70
+ end
39
71
  else
40
- serialize( item )
72
+ not ref.member?( k.to_sym )
41
73
  end
42
74
  end
43
75
  end
76
+
77
+ def initialize
78
+ super()
79
+ replace( {} )
80
+ end
81
+
82
+ def replace( data )
83
+ data = deep_dup( data )
84
+ filter( data )
85
+ hidden( data )
86
+ self
87
+ end
88
+
89
+ private
44
90
 
45
- def filter_data( data, context )
46
- result = {}
91
+ def deep_dup( data )
92
+ data = data.dup
47
93
  data.each do |k,v|
48
- k = k.to_s
49
- case v
50
- when Hash
51
- result[ k ] = filter_data( v,
52
- context[ k ] ) if context.include?( k )
94
+ if v.is_a? Hash
95
+ data[ k ] = deep_dup( v )
96
+ end
97
+ end
98
+ end
99
+
100
+ module ClassMethods
101
+
102
+ def attribute( name, type = nil )
103
+ attributes[ name.to_sym ] = new_instance( type )
104
+ end
105
+
106
+ def hidden( name, type = nil )
107
+ hiddens[ name.to_sym ] = new_instance( type )
108
+ end
109
+
110
+ def data( meth )
111
+ (superclass.send( meth ).dup rescue nil) || {}
112
+ end
113
+ private :data
114
+
115
+ def set( meth, *args )
116
+ args.each { |a| send( meth, a ) }
117
+ end
118
+ private :set
119
+
120
+ def attributes( *args )
121
+ set( :attribute, *args )
122
+ if args.size == 0
123
+ @attributes ||= data( :attributes )
124
+ end
125
+ end
126
+
127
+ def hiddens( *args )
128
+ set( :hidden, *args )
129
+ if args.size == 0
130
+ @hiddens ||= data( :hiddens )
131
+ end
132
+ end
133
+
134
+ def new_instance( type )
135
+ case type
53
136
  when Array
54
- if context.allowed?( k ) || context.include?( k )
55
- result[ k ] = filter_array( v,
56
- context[ k ] )
57
- end
137
+ type[ 0 ].new
138
+ when NilClass
139
+ nil
58
140
  else
59
- result[ k ] = serialize( v ) if context.allowed?( k )
141
+ type.new
60
142
  end
61
143
  end
62
- result
63
144
  end
64
145
  end
65
146
  end