akiva 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +80 -0
  6. data/Guardfile +11 -0
  7. data/LICENSE +9 -0
  8. data/README.md +131 -0
  9. data/Rakefile +5 -0
  10. data/akiva.gemspec +38 -0
  11. data/lib/akiva.rb +11 -0
  12. data/lib/akiva/brain.rb +47 -0
  13. data/lib/akiva/cli.rb +58 -0
  14. data/lib/akiva/core_brain/actions/get_answers_from_subjects_and_properties.rb +73 -0
  15. data/lib/akiva/core_brain/actions/preparators/compare_two_subjects_properties_from_comparison_adjective.rb +19 -0
  16. data/lib/akiva/core_brain/actions/preparators/extract_property_from_comparison_adjective.rb +10 -0
  17. data/lib/akiva/core_brain/actions/preparators/regroup_separated_subjects.rb +10 -0
  18. data/lib/akiva/core_brain/actions/preparators/sort_answers_by_units.rb +35 -0
  19. data/lib/akiva/core_brain/actions/template.rb +23 -0
  20. data/lib/akiva/core_brain/filters/get_answers_from_subjects_and_properties.rb +15 -0
  21. data/lib/akiva/core_brain/filters/template.rb +9 -0
  22. data/lib/akiva/core_brain/formatters/boolean_from_comparison.rb +17 -0
  23. data/lib/akiva/core_brain/formatters/list_all_answers.rb +28 -0
  24. data/lib/akiva/core_brain/formatters/template.rb +19 -0
  25. data/lib/akiva/core_brain/helpers/comparison_adjectives_to_properties.rb +151 -0
  26. data/lib/akiva/core_brain/helpers/misc.rb +28 -0
  27. data/lib/akiva/core_brain/helpers/units.rb +167 -0
  28. data/lib/akiva/core_brain/loader.rb +3 -0
  29. data/lib/akiva/question.rb +88 -0
  30. data/lib/akiva/version.rb +9 -0
  31. data/spec/lib/akiva/brain_spec.rb +89 -0
  32. data/spec/lib/akiva/core_brain/actions/get_answers_from_subjects_and_properties_spec.rb +77 -0
  33. data/spec/lib/akiva/core_brain/actions/preparators/compare_two_subjects_properties_from_comparison_adjective_spec.rb +22 -0
  34. data/spec/lib/akiva/core_brain/actions/preparators/extract_property_from_comparison_adjective_spec.rb +11 -0
  35. data/spec/lib/akiva/core_brain/actions/preparators/regroup_separated_subjects_spec.rb +11 -0
  36. data/spec/lib/akiva/core_brain/actions/preparators/sort_answers_by_units_spec.rb +36 -0
  37. data/spec/lib/akiva/core_brain/filters/get_answers_from_subjects_and_properties_spec.rb +44 -0
  38. data/spec/lib/akiva/core_brain/formatters/boolean_from_comparison_spec.rb +38 -0
  39. data/spec/lib/akiva/core_brain/formatters/list_all_answers_spec.rb +60 -0
  40. data/spec/lib/akiva/core_brain/helpers/misc_spec.rb +26 -0
  41. data/spec/lib/akiva/core_brain/helpers/units_spec.rb +141 -0
  42. data/spec/lib/akiva/core_brain/question_spec.rb +170 -0
  43. data/spec/spec_helper.rb +37 -0
  44. data/spec/support/akiva_brain_helpers.rb +13 -0
  45. data/spec/support/akiva_statements_helpers.rb +66 -0
  46. metadata +75 -16
@@ -0,0 +1,19 @@
1
+ Akiva::Brain.update do
2
+
3
+ add_action :compare_two_subjects_properties_from_comparison_adjective do |response|
4
+ answers_values = response[:answers].map{|hash| hash.last.first.last }
5
+
6
+ begin
7
+ units = Akiva::Brain::Helpers::Units.new(answers_values)
8
+ units.compare # in the future, you may want to pass a multiplicator here
9
+ rescue
10
+ # we fail silently for now, as the error probably comes from the data in TheBigDB anyway,
11
+ # which could well be invalid (= not convertible units)
12
+ else
13
+ property_comparator = Akiva::Brain::Helpers::ComparisonAdjectivesToProperties[response[:filter_captures]["comparison_adjective"]][:comparator]
14
+ response[:comparison_boolean_result] = (units.result == property_comparator)
15
+ end # begin
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,10 @@
1
+ Akiva::Brain.update do
2
+
3
+ add_action :extract_property_from_comparison_adjective do |response|
4
+
5
+ # Note: for now, we're only working with the first property listed for the adjective
6
+ response[:defined_properties] = [Akiva::Brain::Helpers::ComparisonAdjectivesToProperties[response[:filter_captures]["comparison_adjective"]][:properties].first]
7
+
8
+ end
9
+
10
+ end
@@ -0,0 +1,10 @@
1
+ Akiva::Brain.update do
2
+
3
+ add_action :regroup_separated_subjects do |response|
4
+ response[:defined_subjects] ||= []
5
+ response[:filter_captures].each_pair do |name, capture|
6
+ response[:defined_subjects] << Akiva::Brain::Helpers.cleanup_articles(capture) if name =~ /\Asubject\d+/
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,35 @@
1
+ Akiva::Brain.update do
2
+
3
+ add_action :sort_answers_by_units do |response|
4
+ # This is supposed to sort one answer for one property for multiple subjects,
5
+ # you may want to create another action to do something more.
6
+
7
+ answers_values = response[:answers].map{|hash| hash.last.first.last }
8
+
9
+ begin
10
+ units = Akiva::Brain::Helpers::Units.new(answers_values)
11
+ units.sort
12
+ rescue
13
+ # we fail silently for now, as the error probably comes from the data in TheBigDB anyway,
14
+ # which could well be invalid (= not convertible units)
15
+ else
16
+ response[:sorted_answers_by_units] = []
17
+ units.result.each do |instantiated_value|
18
+ response[:answers].each do |hash|
19
+ if instantiated_value == hash.last.first.last
20
+ response[:sorted_answers_by_units] <<
21
+ {
22
+ hash.first => {
23
+ hash.last.first.first => {
24
+ value: instantiated_value.to_s
25
+ }
26
+ }
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end # begin
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,23 @@
1
+ # Akiva::Brain.update do
2
+ #
3
+ # add_action :name_of_action do |response|
4
+ # # 'response' is the same hash passed to all before_actions and to the action itself
5
+ # # The following keys are set from the start:
6
+ # response[:filter_matched] => {regex: /[original regex capturing the following (?<stuff_captured>.+)/, action: :name_of_action, [other options]}
7
+ # response[:filter_captures] => Hash of the captures made in the regex e.g. {"stuff_captured" => "words captured from the question"}
8
+ # end
9
+ #
10
+ # # If you're going to work with a huge action, you may want to pass a class instance instead of a block,
11
+ # # the method #process will be called with the current response as an argument.
12
+ # # The important difference is that you must return the new response when exiting #process, instead of modifying "response" as you do in blocks
13
+ #
14
+ # class MyCustomAction
15
+ # def process(response)
16
+ # # do stuff
17
+ # return new_response
18
+ # end
19
+ # end
20
+ #
21
+ # add_action :name_of_action, MyCustomAction.new
22
+ #
23
+ # end
@@ -0,0 +1,15 @@
1
+ Akiva::Brain.update do
2
+ # The priority is based upon order of creation: last created -> highest priority.
3
+
4
+ add_filter :get_answers_from_subjects_and_properties,
5
+ /\A(?:What (?:is|are)|What's) the (?<properties>.+?) of (?:a |an |the )?(?<subjects>.+?)(?: \?)?\z/i,
6
+ formatter: :list_all_answers
7
+
8
+ add_filter :get_answers_from_subjects_and_properties,
9
+ /\AIs (?<subject1>.+?) (?<comparison_adjective>(#{Akiva::Brain::Helpers::ComparisonAdjectivesToProperties.keys.join("|")})?) than (?<subject2>.+?)(?: \?)?\z/i,
10
+ before_action: [:regroup_separated_subjects, :extract_property_from_comparison_adjective],
11
+ after_action: [:compare_two_subjects_properties_from_comparison_adjective],
12
+ formatter: :boolean_from_comparison
13
+
14
+
15
+ end
@@ -0,0 +1,9 @@
1
+ # Akiva::Brain.update do
2
+ #
3
+ # add_filter :name_of_the_action_that_will_be_called,
4
+ # /regex matching that will trigger this action/i,
5
+ # before_action: [:pre_action_one, :pre_action_two, [...]], # will be executed in this order
6
+ # after_action: [:post_action_one, :post_action_two, [...]], # will be executed in this order
7
+ # formatter: :name_of_formatter
8
+ #
9
+ # end
@@ -0,0 +1,17 @@
1
+ Akiva::Brain.update do
2
+
3
+ add_formatter :boolean_from_comparison do |response|
4
+ if response.has_key?(:comparison_boolean_result)
5
+ if response[:comparison_boolean_result]
6
+ response[:formatted] = "Yes"
7
+ else
8
+ response[:formatted] = "No"
9
+ end
10
+
11
+ if response.has_key?(:actions_chain) and response[:actions_chain].include?(:compare_two_subjects_properties_from_comparison_adjective)
12
+ response[:formatted] += " (#{Akiva::Brain.formatters[:list_all_answers].call(response)})"
13
+ end
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,28 @@
1
+ Akiva::Brain.update do
2
+
3
+ add_formatter :list_all_answers do |response|
4
+
5
+ describe_properties = lambda do |subject|
6
+ if (properties = response[:properties][subject]).size == 1 # if there is only one property
7
+ response[:answers][subject][properties.first]
8
+ else # if there are multiple properties
9
+ answers = response[:answers][subject].values
10
+ properties.map.with_index do |property, i|
11
+ property.capitalize + ": " + answers[i]
12
+ end.join(", ")
13
+ end
14
+ end
15
+
16
+ if response[:subjects]
17
+ if response[:subjects].size == 1 # if there's only one subject
18
+ response[:formatted] = describe_properties.call(response[:subjects].first)
19
+ else # if there are multiple subjects
20
+ response[:formatted] = response[:subjects].map do |subject|
21
+ subject + " => " + describe_properties.call(subject)
22
+ end.join("; ")
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,19 @@
1
+ # Akiva::Brain.update do
2
+ #
3
+ # add_formatter :formatter_name do |response|
4
+ # # you must set response[:formatted] as a textual answer to the question
5
+ # end
6
+ #
7
+ # # If you're going to work with a huge formatter, you may want to pass a class instance instead of a block,
8
+ # # the method #process will be called with the current response as an argument.
9
+ # # The important difference is that you must return the new response when exiting #process, instead of modifying "response" as you do in blocks
10
+ #
11
+ # class MyCustomFormatter
12
+ # def process(response)
13
+ # # do stuff
14
+ # return new_response
15
+ # end
16
+ # end
17
+ #
18
+ # add_formatter :name_of_action, MyCustomFormatter.new
19
+ # end
@@ -0,0 +1,151 @@
1
+ module Akiva
2
+ module Brain
3
+ module Helpers
4
+ ComparisonAdjectivesToProperties = {
5
+ "bigger" => {properties: %w(size), comparator: "superior"},
6
+ "blacker" => {properties: %w(blackness), comparator: "superior"},
7
+ "bolder" => {properties: %w(boldness), comparator: "superior"},
8
+ "braver" => {properties: %w(courage), comparator: "superior"},
9
+ "brighter" => {properties: %w(brightness), comparator: "superior"},
10
+ "busier" => {properties: %w(business), comparator: "superior"},
11
+ # "cleaner" => {properties: %w(cleanliness)},
12
+ "clearer" => {properties: %w(clearness), comparator: "superior"},
13
+ # "cleverer" => {properties: %w(cleverness)},
14
+ "colder" => {properties: %w(temperature), comparator: "inferior"},
15
+ "cooler" => {properties: %w(temperature), comparator: "inferior"},
16
+ "darker" => {properties: %w(luminosity), comparator: "inferior"},
17
+ # "dearer" => {properties: %w(dearness)},
18
+ "deeper" => {properties: %w(depth), comparator: "superior"},
19
+ # "dirtier" => {properties: %w(dirtiness)},
20
+ "drier" => {properties: %w(humidity), comparator: "inferior"},
21
+ # "easier" => {properties: %w(easiness)},
22
+ # "fairer" => {properties: %w(fairness)},
23
+ "faster" => {properties: %w(speed), comparator: "superior"},
24
+ "fatter" => {properties: %w(fatness), comparator: "superior"},
25
+ # "finer" => {properties: %w()},
26
+ "funnier" => {properties: %w(funniness), comparator: "superior"},
27
+ "greater" => {properties: %w(greatness), comparator: "superior"},
28
+ "greener" => {properties: %w(greeness), comparator: "superior"},
29
+ # "happier" => {properties: %w(happiness)},
30
+ # "harder" => {properties: %w(hardness)},
31
+ "healthier" => {properties: %w(healthiness)},
32
+ "heavier" => {properties: ["weight", "average weight"], comparator: "superior"},
33
+ # "higher" => {properties: %w(highness)},
34
+ "hotter" => {properties: %w(temperature), comparator: "superior"},
35
+ # "kinder" => {properties: %w(kindness)},
36
+ "larger" => {properties: %w(size), comparator: "superior"},
37
+ # "later" => {properties: %w(timing)},
38
+ # "lazier" => {properties: %w(laziness)},
39
+ "lighter" => {properties: ["weight", "average weight"], comparator: "inferior"},
40
+ "longer" => {properties: %w(size duration), comparator: "superior"},
41
+ # "lower" => {properties: %w(lowerness)},
42
+ # "luckier" => {properties: %w(luck)},
43
+ # "madder" => {properties: %w(madness)},
44
+ # "merrier" => {properties: %w(merriness)},
45
+ # "narrower" => {properties: %w(narrowness)},
46
+ # "naughtier" => {properties: %w(naughtiness)},
47
+ # "nearer" => {properties: %w(nearness)},
48
+ "newer" => {properties: ["age", "creation date", "release date"], comparator: "inferior"},
49
+ # "noiser" => {properties: %w(noisiness)},
50
+ "older" => {properties: ["age", "creation date", "release date"], comparator: "superior"},
51
+ # "paler" => {properties: %w(paleness)},
52
+ "poorer" => {properties: ["net worth"], comparator: "inferior"},
53
+ # "prettier" => {properties: %w(prettiness)},
54
+ # "prouder" => {properties: %w(proudness)},
55
+ "quicker" => {properties: %w(speed), comparator: "superior"},
56
+ # "redder" => {properties: %w(redness)},
57
+ "richer" => {properties: ["net worth"], comparator: "superior"},
58
+ # "sadder" => {properties: %w(sadness)},
59
+ # "saffer" => {properties: %w(safeness)},
60
+ # "shallower" => {properties: %w(shallowness)},
61
+ # "sharper" => {properties: %w(sharpness)},
62
+ "shorter" => {properties: %w(size duration), comparator: "inferior"},
63
+ # "shallower" => {properties: %w(shallowness)},
64
+ "slower" => {properties: %w(speed), comparator: "inferior"},
65
+ "smaller" => {properties: %w(size duration), comparator: "inferior"},
66
+ # "smoother" => {properties: %w(smoothness)},
67
+ "stronger" => {properties: %w(power), comparator: "superior"},
68
+ # "sweeter" => {properties: %w(sweetness)},
69
+ "taller" => {properties: %w(height size), comparator: "superior"},
70
+ # "thicker" => {properties: %w(thickness)},
71
+ "thinner" => {properties: %w(size), comparator: "inferior"},
72
+ "tinier" => {properties: %w(size), comparator: "inferior"},
73
+ # "uglier" => {properties: %w(ugliness)},
74
+ "warmer" => {properties: %w(temperature), comparator: "superior"},
75
+ "weakness" => {properties: %w(power), comparator: "inferior"},
76
+ "wealthier" => {properties: ["net worth"], comparator: "superior"},
77
+ "wetter" => {properties: %w(humidity), comparator: "superior"},
78
+ # "whither" => {properties: %w()},
79
+ "wider" => {properties: %w(wideness size), comparator: "superior"},
80
+ # "wilder" => {properties: %w(wildness)},
81
+ # "wiser" => {properties: %w(wiseness)},
82
+ "younger" => {properties: %w(age), comparator: "inferior"},
83
+
84
+
85
+ "more ancient" => {properties: ["age", "creation date", "release date"], comparator: "inferior"},
86
+ # "more beautiful" => {properties: %w(looks)},
87
+ # "more brilliant" => {properties: %w(brilliantness)},
88
+ # "more careful" => {properties: %w(carefulness)},
89
+ # "more careless" => {properties: %w(carefulness)},
90
+ # "more cheerful" => {properties: %w(cheerfulness)},
91
+ # "more comfortable" => {properties: %w(comfortableness)},
92
+ # "more dangerous" => {properties: %w(dangerousness)},
93
+ # "more delightful" => {properties: %w(delightfulness)},
94
+ # "more difficult" => {properties: %w(difficultness)},
95
+ # "more enjoyable" => {properties: %w(enjoyability)},
96
+ # "more foolish" => {properties: %w(foolishness)},
97
+ # "more forgetful" => {properties: %w(forgetfulness)},
98
+ # "more frightening" => {properties: %w(frighteningness)},
99
+ # "more generous" => {properties: %w(generousness)},
100
+ # "more handsome" => {properties: %w(handsomeness)},
101
+ # "more helpful" => {properties: %w(helpfulness)},
102
+ # "more ignorant" => {properties: %w(ignorantness)},
103
+ # "more important" => {properties: %w(importantness)},
104
+ # "more intelligent" => {properties: %w(intelligentness)},
105
+ # "more interesting" => {properties: %w(interestingness)},
106
+ # "more pleasant" => {properties: %w(pleasantness)},
107
+ "more powerful" => {properties: %w(power), comparator: "superior"},
108
+ "more prosperous" => {properties: ["gross domestic product"], comparator: "superior"},
109
+ # "more sensible" => {properties: %w(sensibleness)},
110
+ # "more terrible" => {properties: %w(terribleness)},
111
+ # "more thoughtful" => {properties: %w(thoughtfulness)},
112
+ # "more unusual" => {properties: %w(unusualness)},
113
+ # "more useful" => {properties: %w(usefulness)},
114
+ "more valuable" => {properties: ["worth", "price"], comparator: "superior"},
115
+ # "more wonderful" => {properties: %w(wonderfulness)},
116
+
117
+ "less ancient" => {properties: ["age", "creation date", "release date"], comparator: "inferior"},
118
+ # "less beautiful" => {properties: %w(looks)},
119
+ # "less brilliant" => {properties: %w(brilliantness)},
120
+ # "less careful" => {properties: %w(carefulness)},
121
+ # "less careless" => {properties: %w(carefulness)},
122
+ # "less cheerful" => {properties: %w(cheerfulness)},
123
+ # "less comfortable" => {properties: %w(comfortableness)},
124
+ # "less dangerous" => {properties: %w(dangerousness)},
125
+ # "less delightful" => {properties: %w(delightfulness)},
126
+ # "less difficult" => {properties: %w(difficultness)},
127
+ # "less enjoyable" => {properties: %w(enjoyability)},
128
+ # "less foolish" => {properties: %w(foolishness)},
129
+ # "less forgetful" => {properties: %w(forgetfulness)},
130
+ # "less frightening" => {properties: %w(frighteningness)},
131
+ # "less generous" => {properties: %w(generousness)},
132
+ # "less handsome" => {properties: %w(handsomeness)},
133
+ # "less helpful" => {properties: %w(helpfulness)},
134
+ # "less ignorant" => {properties: %w(ignorantness)},
135
+ # "less important" => {properties: %w(importantness)},
136
+ # "less intelligent" => {properties: %w(intelligentness)},
137
+ # "less interesting" => {properties: %w(interestingness)},
138
+ # "less pleasant" => {properties: %w(pleasantness)},
139
+ "less powerful" => {properties: %w(power), comparator: "superior"},
140
+ "less prosperous" => {properties: ["gross domestic product"], comparator: "superior"},
141
+ # "less sensible" => {properties: %w(sensibleness)},
142
+ # "less terrible" => {properties: %w(terribleness)},
143
+ # "less thoughtful" => {properties: %w(thoughtfulness)},
144
+ # "less unusual" => {properties: %w(unusualness)},
145
+ # "less useful" => {properties: %w(usefulness)},
146
+ "less valuable" => {properties: ["worth", "price"], comparator: "superior"},
147
+ # "less wonderful" => {properties: %w(wonderfulness)},
148
+ }
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,28 @@
1
+ module Akiva
2
+ module Brain
3
+ module Helpers
4
+
5
+ def self.degroup_multiple_values(string)
6
+ # NOTE: we probably should check the dictionary here to improve the values detections,
7
+ # and limit the number of requests made.
8
+ values = []
9
+
10
+ string.split(" && ").each do |sub0|
11
+ sub0.split(",").each do |sub1|
12
+ sub1.split(" and ").each do |sub2|
13
+ val = sub2.strip
14
+ val.gsub!(/\A(a|an|the) /i, "")
15
+ values << val
16
+ end
17
+ end
18
+ end
19
+
20
+ values.uniq
21
+ end
22
+
23
+ def self.cleanup_articles(string)
24
+ string.gsub(/\A(a|an|the) /i, "")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,167 @@
1
+ module Akiva
2
+ module Brain
3
+ module Helpers
4
+ class Units
5
+ class UnitNotRecognizedError < StandardError; end
6
+ class IncompatibleUnitsError < StandardError; end
7
+ class TooLongToInstantiateError < StandardError; end
8
+ class NeedTwoValuesToCompareError < StandardError; end
9
+ class CantCompareMoreThanTwoValuesError < StandardError; end
10
+ class InputMustBeAnArray < StandardError; end
11
+
12
+ attr_reader :input, :result, :instantiated_values, :first_value, :last_value
13
+
14
+ def initialize(input)
15
+ @input = input
16
+ end
17
+
18
+ def compare(options = {})
19
+ check_presence_of_values
20
+ check_type_of_values
21
+ check_length_of_values_for_comparison
22
+ instantiate_values
23
+ check_compatibility_of_units
24
+
25
+ @first_value = @instantiated_values.first
26
+ @last_value = @instantiated_values.last
27
+
28
+ if multiplicators = options[:multiplicators]
29
+ @first_value = (@first_value * multiplicators[0]) if multiplicators[0]
30
+ @last_value = (@last_value * multiplicators[1]) if multiplicators[1]
31
+ end
32
+
33
+ @first_value, @last_value = self.class.adjust_units(@first_value, @last_value)
34
+
35
+ if @first_value > @last_value
36
+ @result = "superior"
37
+ elsif @first_value < @last_value
38
+ @result = "inferior"
39
+ else
40
+ @result = "equal"
41
+ end
42
+ end
43
+
44
+ def sort
45
+ check_presence_of_values
46
+ check_type_of_values
47
+ check_maximum_length_of_values
48
+ instantiate_values
49
+ check_compatibility_of_units
50
+
51
+ @result = @instantiated_values.sort
52
+ end
53
+
54
+ def convert(new_unit = "")
55
+ instantiate_values
56
+
57
+ begin
58
+ new_instantiated_value = @instantiated_value.convert_to(new_unit)
59
+ @result = new_instantiated_value.scalar.to_f.to_s
60
+ @result = @result[0..@result.size-3] if @result.match(/\.0$/) # 135.0 => 135
61
+ rescue ArgumentError => error_string
62
+ if error_string.to_s.include?("Unit not recognized") or error_string.to_s.include?("No Unit Specified")
63
+ raise UnitNotRecognizedError
64
+ elsif error_string.to_s.include?("Incompatible Units")
65
+ raise IncompatibleUnitsError
66
+ else
67
+ raise
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ def self.adjust_units(value_1, value_2)
74
+ if ((value_1.to_s.include?("e+") or value_1.to_s.include?("e-")) and (!value_2.to_s.include?("e+") and !value_2.to_s.include?("e-"))) or value_1.scalar.to_s.size > value_2.scalar.to_s.size
75
+ value_1 = value_1.convert_to(value_2)
76
+ elsif ((!value_1.to_s.include?("e+") and !value_1.to_s.include?("e-")) and (value_2.to_s.include?("e+") or value_2.to_s.include?("e-"))) or value_1.scalar.to_s.size < value_2.scalar.to_s.size
77
+ value_2 = value_2.convert_to(value_1)
78
+ end
79
+
80
+ [value_1, value_2]
81
+ end
82
+
83
+ private
84
+ def check_presence_of_value
85
+ if @input.nil?
86
+ raise NeedTwoValuesToCompareError
87
+ end
88
+ end
89
+
90
+ def check_presence_of_values
91
+ if @input.nil?
92
+ raise NeedTwoValuesToCompareError
93
+ end
94
+ end
95
+
96
+ def check_type_of_values
97
+ unless @input.is_a?(Array) or @input.is_a?(Hash)
98
+ raise InputMustBeAnArray
99
+ end
100
+ end
101
+
102
+ def check_length_of_values_for_comparison
103
+ if @input.size < 2
104
+ raise NeedTwoValuesToCompareError
105
+ elsif @input.size > 2
106
+ raise CantCompareMoreThanTwoValuesError
107
+ end
108
+ end
109
+
110
+ def check_maximum_length_of_values
111
+ if @input.size > 100
112
+ raise CantCompareMoreThanTwoValuesError
113
+ end
114
+ end
115
+
116
+ def instantiate_values
117
+ # we accept strings here specially for the "convert" action
118
+ # everywhere else it is filtered with check_type_of_values
119
+
120
+ if @input.is_a?(String)
121
+ values_strings = [@input]
122
+ elsif @input.is_a?(Hash)
123
+ values_strings = @input.values
124
+ else
125
+ values_strings = @input
126
+ end
127
+
128
+ begin
129
+ # we check how much time it takes because it can be REALLY slow be big textual values
130
+ # e.g. "900000000000000000000000000000000000 meters" took 5secs to instantiate (!)
131
+ Timeout::timeout(0.1) do
132
+ if @input.is_a?(String)
133
+ @instantiated_value = Unit(@input)
134
+ elsif values_strings.is_a?(Array)
135
+ @instantiated_values = values_strings.map{|_| Unit(_) }
136
+ end
137
+ end
138
+ rescue Timeout::Error
139
+ raise CantCompareMoreThanTwoValuesError
140
+ return false
141
+ rescue ArgumentError => error_string
142
+ if error_string.to_s.include?("Unit not recognized")
143
+ raise UnitNotRecognizedError
144
+ return false
145
+ else
146
+ raise # error unknown
147
+ end
148
+ end
149
+ end
150
+
151
+ def check_compatibility_of_units
152
+ # we simply check if it can be sorted
153
+ begin
154
+ @instantiated_values.sort
155
+ rescue ArgumentError => error_string
156
+ if error_string.to_s.include?("Incompatible Units")
157
+ raise IncompatibleUnitsError.new(error_string)
158
+ else
159
+ raise
160
+ end
161
+ end
162
+ end
163
+
164
+ end
165
+ end
166
+ end
167
+ end