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.
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