Converter 1.0.2.0 → 1.0.3.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.
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: