Converter 1.0.2.0 → 1.0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/Converter.rb +61 -78
  2. metadata +1 -1
data/lib/Converter.rb CHANGED
@@ -4,125 +4,108 @@ module Converter
4
4
  def self.included(base)
5
5
  base.extend(ClassConverter)
6
6
  end
7
+
8
+ def convert_to target_class
9
+ Converter.convert self, target_class
10
+ end
7
11
 
8
- # Create new Target_Type instance according to Conversion definition
12
+ # Create new Target_Type instance according to the Conversion definition
13
+ # one of the classes (source.class or target_type) should include Converter module
9
14
  # @param [Any Class] source instance to copy from
10
15
  # @param [class] target_type the result type
11
- # @return instance of target_type with data from source
16
+ # @return instance of target_type with data converted from source
12
17
  def self.convert(source, target_type, hash = {})
13
- # Create new target instance
14
- if(converted_target = hash[source])
15
- return converted_target
18
+ # Check if the object has already been converted (Circular pointing)
19
+ if(converted_object = hash[source])
20
+ return converted_object
16
21
  end
17
22
 
18
23
  # Create new target instance
19
24
  hash[source] = target = target_type.new
20
-
25
+
21
26
  # Gets source Conversion definition
22
- conversion_properties = source.class.class_eval { @attribute_converter}
27
+ # Check which one includes Converter module
28
+ convertable_object = get_convertable_object source, target
29
+ conversion_metadatas = convertable_object.class.class_eval { @attribute_converter}
23
30
 
24
31
  # update each accessor on the target according to the attr_converters
25
- source.instance_variables.each do |var|
26
- var_name = var.to_s.delete('@').to_sym
27
-
28
- # Get the conversion definition for the current accessor if exists
29
- if convert_property = conversion_properties[var_name]
30
- target_property_name = convert_property.target_property_name.to_s.concat('=').to_sym
31
-
32
- # Convert from one type to another (by default doesn't do anything)
33
- if convert_property.convert_block.parameters.count == 1
34
- target_value = convert_property.convert_block.call(source.send(var_name))
35
- else
36
- target_value = convert_property.convert_block.call(source.send(var_name), hash)
37
- end
38
-
39
- target.send(target_property_name, target_value)
40
- end
32
+ conversion_metadatas.values.each do |conversion_metadata|
33
+ convert_one_attribute source, target, conversion_metadata, source == convertable_object, hash
41
34
  end
42
35
 
43
36
  target
44
37
  end
45
38
 
46
- # Create new source_type instance according to attr_converters
47
- # @param [Any Class] target instance to copy from
48
- # @param [class] source_type the result type
49
- # @return instance of source_type with data from source
50
- def self.convert_back(target, source_type, hash = {})
51
- # Create new target instance
52
- if(converted_source = hash[target])
53
- return converted_source
39
+ private
40
+ def self.get_convertable_object source, target
41
+ if source.class.included_modules.include? Converter
42
+ source
43
+ elsif target.class.included_modules.include? Converter
44
+ target
45
+ else
46
+ raise ArgumentError.new "One of the given classes should include Converter module"
47
+ end
54
48
  end
55
49
 
56
- # Create new source instance
57
- hash[target] = source = source_type.new
50
+ def self.convert_one_attribute source, target, conversion_metadata, is_source_convertable, hash
51
+ source_attribute_name = is_source_convertable ? conversion_metadata.convertable_attribute_name : conversion_metadata.poro_attribute_name
52
+ convert_block = is_source_convertable ? conversion_metadata.convert_from_convertable_block : conversion_metadata.convert_from_poro_block
53
+ target_attribute_name = is_source_convertable ? conversion_metadata.poro_attribute_name : conversion_metadata.convertable_attribute_name
54
+ target_attribute_name = target_attribute_name.to_s.concat('=').to_sym
58
55
 
59
- # Gets source Conversion definition
60
- conversion_properties = source.class.class_eval { @attribute_converter }
61
-
62
- # update each accessor on the target according to the conversion definition
63
- source.methods.grep(/[a-zA-Z0-9]=$/).each do |var_name|
64
- var_name_trimmed = var_name.to_s.delete('=').to_sym
65
-
66
- # Get the conversion definition for the current accessor if exists
67
- if convert_property = conversion_properties[var_name_trimmed]
68
- target_property_name = convert_property.target_property_name
69
-
70
- # Convert from one type to another (by default doesn't do anything)
71
- if convert_property.convert_back_block.parameters.count == 1
72
- source_value = convert_property.convert_back_block.call(target.send(target_property_name))
73
- else
74
- source_value = convert_property.convert_back_block.call(target.send(target_property_name), hash)
75
- end
76
-
77
- source.send(var_name, source_value)
56
+ # Convert from one type to another (by default doesn't do anything)
57
+ if convert_block.parameters.count == 1
58
+ target_value = convert_block.call(source.send(source_attribute_name))
59
+ else
60
+ target_value = convert_block.call(source.send(source_attribute_name), hash)
78
61
  end
62
+
63
+ target.send(target_attribute_name, target_value)
79
64
  end
80
65
 
81
- source
82
- end
66
+ public
83
67
 
84
68
  # This module add class extension of attr_converter
85
69
  module ClassConverter
86
70
  # Create an attr_accessor and map this attribute as convertable ,
87
71
  # this means that this attribute will be converted when calling to Convert/
88
- # @param [symbol] symbol attribute name
89
- # @param [symbol] another_name the name of the converted attribute(on the target)
90
- # @param [block] convert_block block that convert the source data type to the target data type
91
- # @param [block] convert_back_block block that convert the target data type to the source data type
92
- def attr_converter(symbol, attr_another_name = nil, convert_block = nil, convert_back_block = nil)
72
+ # @param [symbol] convertable_attribute_name class attribute name
73
+ # @param [symbol] poro_attribute_name the attribute name of a poro class (plain old ruby object)
74
+ # @param [block] convert_block block that convert between the convetable attribute class and the poro attribute class
75
+ # @param [block] convert_back_block block that convert between the poro attribute class and the convetable attribute class
76
+ def attr_converter(convertable_attribute_name, poro_attribute_name = nil, convert_block = nil, convert_back_block = nil)
93
77
  # Set default values for nil arguments
94
- attr_another_name ||= symbol
78
+ poro_attribute_name ||= convertable_attribute_name
95
79
  @attribute_converter ||= {}
96
80
 
97
81
  if convert_block.class == Symbol
98
- source_type = convert_block.to_s
99
- target_type = convert_back_block.to_s
100
- convert_block = lambda { |s,h| Converter.convert(s, eval(target_type), h)}
101
- convert_back_block = lambda { |t,h| Converter.convert_back(t, eval(source_type), h)}
82
+ convertable_type = convert_block.to_s
83
+ poro_type = convert_back_block.to_s
84
+ convert_block = lambda { |source, hash| Converter.convert(source, eval(poro_type), hash) }
85
+ convert_back_block = lambda { |source, hash| Converter.convert(source, eval(convertable_type), hash) }
102
86
  else
103
- convert_block ||= lambda { |source, hash| source }
104
- convert_back_block ||= lambda { |target, hash| target }
87
+ convert_block ||= lambda { |source| source }
88
+ convert_back_block ||= lambda { |source| source }
105
89
  end
106
90
 
107
-
108
91
  # Create new ConversionMetadata
109
- @attribute_converter[symbol] =ConversionMetadata.new(symbol, attr_another_name, convert_block, convert_back_block)
110
- attr_accessor symbol
92
+ @attribute_converter[convertable_attribute_name] =ConversionMetadata.new(convertable_attribute_name, poro_attribute_name, convert_block, convert_back_block)
93
+ attr_accessor convertable_attribute_name
111
94
  end
112
95
  end
113
96
 
114
97
  # Represent conversion data of one property to another
115
98
  class ConversionMetadata
116
- def initialize(source_prop_name, target_prop_name, convert, convert_back)
117
- @source_property_name = source_prop_name
118
- @target_property_name = target_prop_name
119
- @convert_block = convert
120
- @convert_back_block = convert_back
99
+ def initialize(convertable_attribute_name, poro_attribute_name, convert_from_convertable_block, convert_from_poro_block)
100
+ @convertable_attribute_name = convertable_attribute_name
101
+ @poro_attribute_name = poro_attribute_name
102
+ @convert_from_convertable_block = convert_from_convertable_block
103
+ @convert_from_poro_block = convert_from_poro_block
121
104
  end
122
105
 
123
- attr_accessor :source_property_name
124
- attr_accessor :target_property_name
125
- attr_accessor :convert_block
126
- attr_accessor :convert_back_block
106
+ attr_accessor :convertable_attribute_name
107
+ attr_accessor :poro_attribute_name
108
+ attr_accessor :convert_from_convertable_block
109
+ attr_accessor :convert_from_poro_block
127
110
  end
128
111
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2.0
4
+ version: 1.0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: