chemistry_paradise 1.4.2

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +657 -0
  3. data/bin/chemistry_paradise +7 -0
  4. data/bin/wetter +7 -0
  5. data/chemistry_paradise.gemspec +46 -0
  6. data/doc/README.gen +595 -0
  7. data/doc/bugs/BUGS.md +16 -0
  8. data/doc/formulas/biochemical_calculations.md +5 -0
  9. data/doc/todo/todo_for_the_chemistry_paradise_project.md +33 -0
  10. data/doc/todo/todo_for_the_wetter_project.md +7 -0
  11. data/lib/chemistry_paradise/base/base.rb +215 -0
  12. data/lib/chemistry_paradise/base/colours.rb +93 -0
  13. data/lib/chemistry_paradise/commandline/help.rb +40 -0
  14. data/lib/chemistry_paradise/commandline/menu.rb +88 -0
  15. data/lib/chemistry_paradise/commandline/parse_commandline.rb +94 -0
  16. data/lib/chemistry_paradise/constants/constants.rb +77 -0
  17. data/lib/chemistry_paradise/constants/constants_for_chemical_formulas.rb +16 -0
  18. data/lib/chemistry_paradise/constants/file_constants.rb +33 -0
  19. data/lib/chemistry_paradise/constants/german_names_of_elements_to_element_symbol.rb +157 -0
  20. data/lib/chemistry_paradise/converters/celsius_to_fahrenheit.rb +143 -0
  21. data/lib/chemistry_paradise/converters/celsius_to_kelvin.rb +125 -0
  22. data/lib/chemistry_paradise/converters/fahrenheit_to_celsius.rb +132 -0
  23. data/lib/chemistry_paradise/converters/shared.rb +21 -0
  24. data/lib/chemistry_paradise/gui/gtk3/calculate_molecular_weight/calculate_molecular_weight.rb +34 -0
  25. data/lib/chemistry_paradise/gui/gtk3/show_periodic_table/show_periodic_table.rb +34 -0
  26. data/lib/chemistry_paradise/gui/gtk3/temperature_converter/temperature_converter.rb +112 -0
  27. data/lib/chemistry_paradise/gui/gtk3/wetter/wetter.rb +119 -0
  28. data/lib/chemistry_paradise/gui/libui/temperature_converter/temperature_converter.rb +100 -0
  29. data/lib/chemistry_paradise/gui/libui/wetter/wetter.rb +47 -0
  30. data/lib/chemistry_paradise/gui/shared_code/calculate_molecular_weight/calculate_molecular_weight_module.rb +171 -0
  31. data/lib/chemistry_paradise/gui/shared_code/show_periodic_table/show_periodic_table_module.rb +318 -0
  32. data/lib/chemistry_paradise/gui/shared_code/temperature_converter/temperature_converter_module.rb +192 -0
  33. data/lib/chemistry_paradise/gui/shared_code/wetter/wetter_module.rb +349 -0
  34. data/lib/chemistry_paradise/gui/swing/TemperatureConverter$1.class +0 -0
  35. data/lib/chemistry_paradise/gui/swing/TemperatureConverter.class +0 -0
  36. data/lib/chemistry_paradise/gui/swing/TemperatureConverter.java +133 -0
  37. data/lib/chemistry_paradise/gui/unified_widgets/wetter/wetter.rb +62 -0
  38. data/lib/chemistry_paradise/images/show_periodic_table.png +0 -0
  39. data/lib/chemistry_paradise/images/vienna_map.png +0 -0
  40. data/lib/chemistry_paradise/interactive_chemistry_shell.rb +246 -0
  41. data/lib/chemistry_paradise/project/project.rb +24 -0
  42. data/lib/chemistry_paradise/requires/common_external_requires.rb +17 -0
  43. data/lib/chemistry_paradise/requires/require_the_project.rb +21 -0
  44. data/lib/chemistry_paradise/requires/require_the_project_including_the_graphical_user_interface.rb +7 -0
  45. data/lib/chemistry_paradise/requires/require_the_project_including_the_web_interface.rb +4 -0
  46. data/lib/chemistry_paradise/shared.rb +130 -0
  47. data/lib/chemistry_paradise/show_electron_configuration.rb +250 -0
  48. data/lib/chemistry_paradise/show_element.rb +145 -0
  49. data/lib/chemistry_paradise/sinatra/sinatra.rb +131 -0
  50. data/lib/chemistry_paradise/sinatra/wetter/app.rb +68 -0
  51. data/lib/chemistry_paradise/sinatra/wetter/start_sinatra_interface.rb +31 -0
  52. data/lib/chemistry_paradise/split_molecule_names.rb +228 -0
  53. data/lib/chemistry_paradise/toplevel_methods/atomgewichte.rb +31 -0
  54. data/lib/chemistry_paradise/toplevel_methods/convert_parens.rb +64 -0
  55. data/lib/chemistry_paradise/toplevel_methods/display_where_the_molmasses_are_kept.rb +24 -0
  56. data/lib/chemistry_paradise/toplevel_methods/e.rb +16 -0
  57. data/lib/chemistry_paradise/toplevel_methods/kelvin.rb +34 -0
  58. data/lib/chemistry_paradise/toplevel_methods/language.rb +50 -0
  59. data/lib/chemistry_paradise/toplevel_methods/misc.rb +228 -0
  60. data/lib/chemistry_paradise/toplevel_methods/periodic_table.rb +16 -0
  61. data/lib/chemistry_paradise/toplevel_methods/remove_this_molecule_from.rb +63 -0
  62. data/lib/chemistry_paradise/toplevel_methods/roebe.rb +16 -0
  63. data/lib/chemistry_paradise/toplevel_methods/show_electron_negativity_chart.rb +26 -0
  64. data/lib/chemistry_paradise/utility_scripts/calculate_atomic_mass.rb +559 -0
  65. data/lib/chemistry_paradise/utility_scripts/combustion_analysis.rb +207 -0
  66. data/lib/chemistry_paradise/utility_scripts/electron_negativity_chart.rb +78 -0
  67. data/lib/chemistry_paradise/utility_scripts/equalize_chemical_formula.rb +84 -0
  68. data/lib/chemistry_paradise/utility_scripts/equation_solver.rb +130 -0
  69. data/lib/chemistry_paradise/utility_scripts/orbitals.rb +70 -0
  70. data/lib/chemistry_paradise/utility_scripts/show_electron_negativity_of_this_element.rb +103 -0
  71. data/lib/chemistry_paradise/utility_scripts/show_periodic_table.rb +996 -0
  72. data/lib/chemistry_paradise/verbose_chemical_calculation.rb +21 -0
  73. data/lib/chemistry_paradise/version/version.rb +19 -0
  74. data/lib/chemistry_paradise/wetter/wetter.rb +539 -0
  75. data/lib/chemistry_paradise/www/wetter/embeddable_interface.rb +78 -0
  76. data/lib/chemistry_paradise/www/wetter/wetter.cgi +28 -0
  77. data/lib/chemistry_paradise/yaml/atomgewichte.yml +139 -0
  78. data/lib/chemistry_paradise/yaml/colours_for_the_elements.yml +13 -0
  79. data/lib/chemistry_paradise/yaml/dichte.yml +21 -0
  80. data/lib/chemistry_paradise/yaml/electron_negativity_chart.yml +111 -0
  81. data/lib/chemistry_paradise/yaml/molecular_formula_of_different_molecules.yml +13 -0
  82. data/lib/chemistry_paradise/yaml/periodic_table_of_the_elements.yml +125 -0
  83. data/lib/chemistry_paradise.rb +1 -0
  84. data/test/testing_chemistry_paradise.rb +49 -0
  85. metadata +175 -0
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'chemistry_paradise/toplevel_methods/periodic_table.rb'
6
+ # =========================================================================== #
7
+ module ChemistryParadise
8
+
9
+ # ========================================================================= #
10
+ # === ChemistryParadise.periodic_table?
11
+ # ========================================================================= #
12
+ def self.periodic_table?
13
+ '/Users/x/DATA/SCIENCE/YAML/periodic_table.yml'
14
+ end
15
+
16
+ end
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'chemistry_paradise/toplevel_methods/remove_this_molecule_from.rb'
6
+ # =========================================================================== #
7
+ require 'chemistry_paradise/split_molecule_names.rb'
8
+
9
+ module ChemistryParadise
10
+
11
+ # ========================================================================= #
12
+ # === ChemistryParadise.remove_this_molecule_from
13
+ #
14
+ # The first argument is the molecule that should be deducted from
15
+ # the formula.
16
+ # ========================================================================= #
17
+ def self.remove_this_molecule_from(
18
+ this_molecule = 'OH',
19
+ from = 'C2H5NO2'
20
+ )
21
+ array_big_molecule = ::ChemistryParadise.split_this_molecular_formula_into_a_hash(from)
22
+ array_this_molecule = ::ChemistryParadise.split_this_molecular_formula_into_a_hash(this_molecule)
23
+ # ======================================================================= #
24
+ # Next, iterate over the small molecule.
25
+ # ======================================================================= #
26
+ array_this_molecule.each {|this_compound|
27
+ unless this_compound =~ /\d+/
28
+ this_compound << '1' # Must be at the least one.
29
+ end
30
+ # ===================================================================== #
31
+ # Select the entry that is the correct one.
32
+ # ===================================================================== #
33
+ this_entry = array_big_molecule.find {|entry|
34
+ entry[0,1] == this_compound[0,1]
35
+ }
36
+ begin
37
+ n_times_in_the_big_molecule = /(\d{1,3})/.match(this_entry)[1].to_i
38
+ n_times_in_the_small_molecule = /(\d{1,3})/.match(this_compound)[1].to_i
39
+ new_n_times = n_times_in_the_big_molecule - n_times_in_the_small_molecule
40
+ new_entry = this_compound[0,1]+new_n_times.to_s
41
+ # ===================================================================== #
42
+ # Now we have the new entry; we need to re-insert it into the big
43
+ # original Array.
44
+ # ===================================================================== #
45
+ proper_index = array_big_molecule.index {|entry|
46
+ entry[0,1] == this_compound[0,1]
47
+ }
48
+ array_big_molecule[proper_index] = new_entry
49
+ rescue NoMethodError => error
50
+ pp error
51
+ end
52
+ }
53
+ return array_big_molecule.join # Join it up again.
54
+ end
55
+
56
+ end
57
+
58
+ if __FILE__ == $PROGRAM_NAME
59
+ puts 'Deducting OH from C2H5NO2 next:'
60
+ puts ::ChemistryParadise.remove_this_molecule_from('OH', 'C2H5NO2')
61
+ puts 'Deducting H2O from C2H5NO2 next:'
62
+ puts ::ChemistryParadise.remove_this_molecule_from('H2O', 'C2H5NO2')
63
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'chemistry_paradise/toplevel_methods/roebe.rb'
6
+ # =========================================================================== #
7
+ module ChemistryParadise
8
+
9
+ # ========================================================================= #
10
+ # === ChemistryParadise.is_on_roebe?
11
+ # ========================================================================= #
12
+ def self.is_on_roebe?
13
+ ENV['IS_ROEBE'].to_s == '1'
14
+ end
15
+
16
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # require 'chemistry_paradise/toplevel_methods/show_electron_negativity_chart.rb'
6
+ # =========================================================================== #
7
+ require 'chemistry_paradise/constants/constants.rb'
8
+
9
+ module ChemistryParadise
10
+
11
+ # ========================================================================= #
12
+ # === ChemistryParadise.show_electron_negativity_chart
13
+ # ========================================================================= #
14
+ def self.show_electron_negativity_chart
15
+ Constants::ELECTRON_NEGATIVITY_CHART.each_pair {|key, value|
16
+ value = value.to_f
17
+ value = '%.2f' % value
18
+ puts key.ljust(2)+' -> '+value.to_s.rjust(2)
19
+ }
20
+ end
21
+
22
+ end
23
+
24
+ if __FILE__ == $PROGRAM_NAME
25
+ ChemistryParadise.show_electron_negativity_chart
26
+ end
@@ -0,0 +1,559 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === ChemistryParadise::CalculateAtomicMass
6
+ #
7
+ # This class will calculate the atomic mass of a compound.
8
+ # =========================================================================== #
9
+ # require 'chemistry_paradise/utility_scripts/calculate_atomic_mass.rb'
10
+ # ChemistryParadise::CalculateAtomicMass.new(ARGV)
11
+ # =========================================================================== #
12
+ require 'chemistry_paradise/base/base.rb'
13
+
14
+ module ChemistryParadise
15
+
16
+ class CalculateAtomicMass < Base # === ChemistryParadise::CalculateAtomicMass
17
+
18
+ require 'chemistry_paradise/split_molecule_names.rb'
19
+
20
+ # ========================================================================= #
21
+ # === NAMESPACE
22
+ # ========================================================================= #
23
+ NAMESPACE = inspect
24
+
25
+ # ========================================================================= #
26
+ # === ARRAY_HELP_OPTIONS
27
+ # ========================================================================= #
28
+ ARRAY_HELP_OPTIONS = %w(
29
+ HELP help --help --h -h
30
+ )
31
+
32
+ # ========================================================================= #
33
+ # === ATOMGEWICHTE
34
+ # ========================================================================= #
35
+ _ = Constants::FILE_ATOMGEWICHTE
36
+ if File.exist? _
37
+ ATOMGEWICHTE = YAML.load_file(_)
38
+ elsif File.exist? File.expand_path('~')+File.basename(_)
39
+ ATOMGEWICHTE = YAML.load_file(File.expand_path('~')+File.basename(_))
40
+ end
41
+
42
+ # ========================================================================= #
43
+ # === ChemistryParadise::CalculateAtomicMass::DEFAULT_INPUT
44
+ # ========================================================================= #
45
+ DEFAULT_INPUT = 'P2O5'
46
+
47
+ # ========================================================================= #
48
+ # === initialize
49
+ # ========================================================================= #
50
+ def initialize(
51
+ optional_input = ARGV,
52
+ run_already = true
53
+ )
54
+ reset
55
+ set_input(optional_input)
56
+ case run_already.to_s
57
+ when 'do_not_report'
58
+ @report_result = false
59
+ run_already = true
60
+ end
61
+ # ======================================================================= #
62
+ # === Handle blocks next
63
+ # ======================================================================= #
64
+ if block_given?
65
+ yielded = yield
66
+ case yielded
67
+ # ===================================================================== #
68
+ # === :do_not_exit
69
+ # ===================================================================== #
70
+ when :do_not_exit
71
+ @may_we_exit = false
72
+ else
73
+ if yielded.is_a? Hash
74
+ _ = yielded
75
+ if _.has_key? :verbosity
76
+ @report_result = _[:verbosity]
77
+ end
78
+ if _.has_key? :may_we_exit
79
+ @may_we_exit =_[:may_we_exit]
80
+ end
81
+ end
82
+ end
83
+ end
84
+ run if run_already
85
+ end
86
+
87
+ # ========================================================================= #
88
+ # === reset
89
+ # ========================================================================= #
90
+ def reset
91
+ super()
92
+ # ======================================================================= #
93
+ # === @commandline_arguments
94
+ # ======================================================================= #
95
+ @commandline_arguments = []
96
+ # ======================================================================= #
97
+ # === @show_more
98
+ # ======================================================================= #
99
+ @show_more = true
100
+ # ======================================================================= #
101
+ # === @show_the_steps
102
+ #
103
+ # If the following variable is set to true then we will display,
104
+ # on the commandline, what is done when. This gives the user more
105
+ # information about what is going on, and it may also help during
106
+ # debugging this class/project.
107
+ #
108
+ # Note that @show_the_steps is a bit different to @show_more, so
109
+ # these two variables are presently kept separate.
110
+ # ======================================================================= #
111
+ @show_the_steps = false
112
+ # ======================================================================= #
113
+ # === @individual_components
114
+ # ======================================================================= #
115
+ @individual_components = []
116
+ # ======================================================================= #
117
+ # === @output_string
118
+ # ======================================================================= #
119
+ @output_string = ''.dup
120
+ # ======================================================================= #
121
+ # === @report_result
122
+ # ======================================================================= #
123
+ @report_result = true
124
+ # ======================================================================= #
125
+ # === @may_we_exit
126
+ # ======================================================================= #
127
+ @may_we_exit = true
128
+ # ======================================================================= #
129
+ # === @molecular_formula_of_different_molecules
130
+ # ======================================================================= #
131
+ @molecular_formula_of_different_molecules = YAML.load_file(
132
+ FILE_MOLECULAR_FORMULA_OF_DIFFERENT_MOLECULES
133
+ )
134
+ set_input
135
+ end
136
+
137
+ # ========================================================================= #
138
+ # === set_input
139
+ # ========================================================================= #
140
+ def set_input(i = DEFAULT_INPUT)
141
+ if i.is_a? Array
142
+ @commandline_arguments = i[1..-1] # Set the remaining as commandline arguments.
143
+ i = i.first # And re-assign the first input.
144
+ end
145
+ i = DEFAULT_INPUT if i.nil?
146
+ case i.to_s
147
+ when 'do_not_report'
148
+ @report_result = false
149
+ i = nil
150
+ when 'harnstoff'
151
+ i = @molecular_formula_of_different_molecules['harnstoff']
152
+ end
153
+ i = ARRAY_TEST_THESE_MOLECULES if i == :test_default_molecules
154
+ i = i.to_s.dup
155
+ # if i.include? ', '
156
+ # i = i.split(',').map(&:strip)
157
+ # end
158
+ # i = [i] unless i.is_a? Array
159
+ @input = i
160
+ sanitize_input
161
+ end
162
+
163
+ # ========================================================================= #
164
+ # === input?
165
+ # ========================================================================= #
166
+ def input?
167
+ @input
168
+ end
169
+
170
+ # ========================================================================= #
171
+ # === sanitize_input_for_element_names
172
+ # ========================================================================= #
173
+ def sanitize_input_for_element_names(array)
174
+ result = []
175
+ if array.any? {|entry| entry == entry.downcase }
176
+ array.each {|entry|
177
+ case entry
178
+ when *ARRAY_HELP_OPTIONS
179
+ show_help :then_exit
180
+ end
181
+ if entry == entry.downcase
182
+ result[-1] = result[-1]+entry
183
+ else
184
+ result << entry
185
+ end
186
+ }
187
+ else
188
+ result = array
189
+ end
190
+ return result
191
+ end
192
+
193
+ # ========================================================================= #
194
+ # === calculate_compound
195
+ #
196
+ # This method will attempt to calculate the given input.
197
+ #
198
+ # The input to this method will usually be something like "Pb3".
199
+ # ========================================================================= #
200
+ def calculate_compound(i)
201
+ result = 0
202
+ if i =~ /\d+/ # if input has a number
203
+ splitted = i.split(/(\d+)/)
204
+ else # else assume that the number is one.
205
+ splitted = [ i, 1 ]
206
+ end
207
+ if atomgewichte?.has_key? splitted[0]
208
+ result = splitted[1].to_i * ATOMGEWICHTE[splitted[0]]
209
+ end
210
+ gather_individual_components(i, result)
211
+ return result
212
+ end; alias ba calculate_compound # === ba
213
+ alias summenformel calculate_compound # === summenformel
214
+ alias atomgewicht calculate_compound # === atomgewicht
215
+ alias molmasse calculate_compound # === molmasse
216
+ alias molare_masse calculate_compound # === molare_masse
217
+ alias calculcate_molecular_weight calculate_compound # === calculcate_molecular_weight
218
+
219
+ # ========================================================================= #
220
+ # === atomgewichte?
221
+ # ========================================================================= #
222
+ def atomgewichte?
223
+ ATOMGEWICHTE
224
+ end
225
+
226
+ # ========================================================================= #
227
+ # === set_result
228
+ # ========================================================================= #
229
+ def set_result(i)
230
+ @result = i
231
+ end
232
+
233
+ # ========================================================================= #
234
+ # === report_result
235
+ # ========================================================================= #
236
+ def report_result
237
+ e @output_string
238
+ end
239
+
240
+ # ========================================================================= #
241
+ # === gather_individual_components
242
+ # ========================================================================= #
243
+ def gather_individual_components(name, weight)
244
+ array = [name, weight]
245
+ @individual_components << array
246
+ end
247
+
248
+ # ========================================================================= #
249
+ # === bold_red
250
+ # ========================================================================= #
251
+ def bold_red(i)
252
+ swarn(i)
253
+ end
254
+
255
+ # ========================================================================= #
256
+ # === nice_result
257
+ # ========================================================================= #
258
+ def nice_result
259
+ @result.to_f.round(3).to_s
260
+ end
261
+
262
+ # ========================================================================= #
263
+ # === is_included?
264
+ # ========================================================================= #
265
+ def is_included?(i = input?)
266
+ i = i.dup
267
+ # ======================================================================= #
268
+ # First remove all numbers from the input:
269
+ # ======================================================================= #
270
+ i.delete!('0-9')
271
+ i = i[0,2] if i.size > 2 # Take only the first two characters, in the event that we have more than two characters in the supplied input.
272
+ atomgewichte?.has_key?(i)
273
+ end; alias include? is_included? # === include?
274
+
275
+ # ========================================================================= #
276
+ # === report_result?
277
+ # ========================================================================= #
278
+ def report_result?
279
+ @report_result
280
+ end
281
+
282
+ # ========================================================================= #
283
+ # === result?
284
+ # ========================================================================= #
285
+ def result?
286
+ @result
287
+ end; alias result result? # === result
288
+ alias masse? result? # === masse?
289
+
290
+ # ========================================================================= #
291
+ # === menu (menu tag)
292
+ #
293
+ # The @commandline_arguments will be checked against the internal menu.
294
+ # ========================================================================= #
295
+ def menu(i = @commandline_arguments)
296
+ if i.is_a? Array
297
+ i.each {|entry| menu(entry) }
298
+ else
299
+ case i # case tag
300
+ # ===================================================================== #
301
+ # === molmasse C5H6N2O2 --english
302
+ # ===================================================================== #
303
+ when /^-?-?english$/
304
+ do_use_the_english_language
305
+ # ===================================================================== #
306
+ # === molmasse C5H6N2O2 --show-steps
307
+ # ===================================================================== #
308
+ when /^-?-?show(-|_)?steps$/
309
+ do_show_the_steps
310
+ # ===================================================================== #
311
+ # === molmasse C5H6N2O2 --show-details
312
+ # ===================================================================== #
313
+ when /^-?-?show(-|_)?details?$/,
314
+ '--detail'
315
+ do_show_details
316
+ # ===================================================================== #
317
+ # === molmasse --help
318
+ # ===================================================================== #
319
+ when *ARRAY_HELP_OPTIONS
320
+ show_help
321
+ exit_the_program
322
+ # ===================================================================== #
323
+ # === molmasse SUM
324
+ # ===================================================================== #
325
+ when 'SUM',
326
+ 'SHOW',
327
+ 'MORE'
328
+ do_show_details
329
+ end
330
+ end
331
+ end; alias check_against_menu menu # === check_against_menu
332
+
333
+ # ========================================================================= #
334
+ # === do_show_details
335
+ # ========================================================================= #
336
+ def do_show_details
337
+ @show_more = true
338
+ end
339
+
340
+ # ========================================================================= #
341
+ # === opnn
342
+ # ========================================================================= #
343
+ def opnn
344
+ super(NAMESPACE)
345
+ end
346
+
347
+ # ========================================================================= #
348
+ # === determine_output_string
349
+ #
350
+ # This method will determine the String that will be shown to the
351
+ # user on the commandline.
352
+ # ========================================================================= #
353
+ def determine_output_string
354
+ _ = nice_result
355
+ if do_we_use_english?
356
+ @output_string = "#{rev}The molecular mass of #{sfancy(@input)} is "\
357
+ "#{simp(_+' u (g / mol)')}."
358
+ else # then we probably use german
359
+ @output_string = "#{rev}Die molekulare Masse von #{sfancy(@input)} "\
360
+ "beträgt #{simp(_+' u (g / mol)')}."
361
+ end
362
+ end
363
+
364
+ # ========================================================================= #
365
+ # === show_help
366
+ # ========================================================================= #
367
+ def show_help(
368
+ i = :then_exit
369
+ )
370
+ opn; e 'Pass -SUM to show the individual sub-steps as well.'
371
+ exit_the_program(i)
372
+ end
373
+
374
+ # ========================================================================= #
375
+ # === consider_modifying_the_output_string
376
+ # ========================================================================= #
377
+ def consider_modifying_the_output_string
378
+ if @show_more # This can modify the output string.
379
+ _ = ''.dup
380
+ Hash[@individual_components].each_pair {|key, value|
381
+ key = key.scan(/./).map {|entry|
382
+ # if entry =~ /^\d+/ # Starts with a number.
383
+ # entry << 'x'
384
+ # end # Disabled as of July 2021. May be re-enabled at a later time.
385
+ entry
386
+ }
387
+ key = key.join
388
+ _ << key+': '+value.round(7).to_s+' | '
389
+ }
390
+ @output_string = @output_string.dup if @output_string.frozen?
391
+ @output_string << "#{N}#{bold_red(' (The individual components were: ').dup}#{rev}"
392
+ _.strip!
393
+ splitted = _.split('|').map {|entry|
394
+ Colours.kde_colour_palette_plasma_blue(entry)
395
+ }
396
+ joined = splitted.join(teal('|'))
397
+ @output_string << joined+
398
+ bold_red(')')
399
+ end
400
+ end
401
+
402
+ # ========================================================================= #
403
+ # === do_show_the_steps
404
+ # ========================================================================= #
405
+ def do_show_the_steps
406
+ @show_the_steps = true
407
+ end
408
+
409
+ # ========================================================================= #
410
+ # === sanitize_input (sanitize tag)
411
+ #
412
+ # This method will presently sanitize the input, by working on ₂ and
413
+ # on ₃, and replace these with the corresponding numbers. This may
414
+ # be useful depending on the chemical formula at hand, such as
415
+ # carbon dioxide (CO₂).
416
+ # ========================================================================= #
417
+ def sanitize_input
418
+ @input.tr!('₂','2') if @input.include? '₂'
419
+ @input.tr!('₃','3') if @input.include? '₃'
420
+ @input.tr!('₄','4') if @input.include? '₄'
421
+ if @input.include? '∙'
422
+ @input.tr!('∙','|')
423
+ end
424
+ end
425
+
426
+ # ========================================================================= #
427
+ # === run (run tag)
428
+ # ========================================================================= #
429
+ def run
430
+ check_against_menu
431
+ use_this_input = input?
432
+ if use_this_input.to_s.size < 3
433
+ unless is_included?
434
+ report_that_this_element_does_not_exist(use_this_input)
435
+ end
436
+ end
437
+ calculate_result
438
+ consider_modifying_the_output_string
439
+ report_result if report_result?
440
+ end
441
+
442
+ # ========================================================================= #
443
+ # === report_that_this_element_does_not_exist
444
+ # ========================================================================= #
445
+ def report_that_this_element_does_not_exist(
446
+ i, may_we_exit = @may_we_exit
447
+ )
448
+ opnn; e 'The given element at `'+sfancy(i.to_s)+'` does not exist.'
449
+ exit_the_program(may_we_exit)
450
+ end
451
+
452
+ # ========================================================================= #
453
+ # === exit_the_program
454
+ # ========================================================================= #
455
+ def exit_the_program(
456
+ may_we_exit = @may_we_exit
457
+ )
458
+ case may_we_exit
459
+ when :then_exit
460
+ may_we_exit = true
461
+ end
462
+ exit if may_we_exit
463
+ end
464
+
465
+ # ========================================================================= #
466
+ # === calculate_result
467
+ #
468
+ # Use this method to calculate the result (the molecular mass).
469
+ #
470
+ # Keep in mind that the input may be somewhat complex, such as
471
+ # "(NH₄)₂SO₄". This has to be expanded first.
472
+ # ========================================================================= #
473
+ def calculate_result(
474
+ i = input?
475
+ )
476
+ mass_number = 0 # This will become the result eventually.
477
+ i.squeeze!(' ')
478
+ # ======================================================================= #
479
+ # Let class SplitMoleculeNames split the components next.
480
+ # ======================================================================= #
481
+ splitted = SplitMoleculeNames.new(i).result
482
+ splitted = sanitize_input_for_element_names(splitted)
483
+ splitted.each {|entry|
484
+ add_this_amount = calculate_compound(entry)
485
+ if @show_the_steps
486
+ e "#{rev}Now adding #{royalblue(add_this_amount)} for the "\
487
+ "compound #{steelblue(entry)}."
488
+ end
489
+ mass_number += add_this_amount
490
+ }
491
+ set_result(mass_number)
492
+ determine_output_string
493
+ end; alias calculate calculate_result # === calculate
494
+
495
+ # ========================================================================= #
496
+ # === ChemistryParadise::CalculateAtomicMass[]
497
+ # ========================================================================= #
498
+ def self.[](i)
499
+ parse(i)
500
+ end
501
+
502
+ # ========================================================================= #
503
+ # === ChemistryParadise::CalculateAtomicMass.parse
504
+ # ========================================================================= #
505
+ def self.parse(i)
506
+ _ = new(i, false)
507
+ _.calculate
508
+ return _.nice_result
509
+ end
510
+
511
+ end
512
+
513
+ # =========================================================================== #
514
+ # === ChemistryParadise.atomic_mass_of
515
+ #
516
+ # This method is a shortcut, to quickly calculate the molecular mass of
517
+ # a compound. See the usage example that follows.
518
+ #
519
+ # Usage examples:
520
+ #
521
+ # ChemistryParadise.atomic_mass_of 'C10H13N5O3' # => "251.245"
522
+ # ChemistryParadise.atomic_mass_of 'H2O' # => "18.015"
523
+ #
524
+ # =========================================================================== #
525
+ def self.atomic_mass_of(i)
526
+ ChemistryParadise::CalculateAtomicMass.parse(i)
527
+ end; self.instance_eval { alias return_molmasse atomic_mass_of } # === Chemistry.return_molmasse
528
+ self.instance_eval { alias molmass_of? atomic_mass_of } # === Chemistry.molmass_of?
529
+ self.instance_eval { alias compound_mass? atomic_mass_of } # === Chemistry.compound_mass?
530
+
531
+ end
532
+
533
+ if __FILE__ == $PROGRAM_NAME
534
+ include ChemistryParadise
535
+ if ARGV.empty?
536
+ alias e puts
537
+ opn; e 'Running some tests now as no input was given to us.'
538
+ # ======================================================================= #
539
+ # === test_me
540
+ # ======================================================================= #
541
+ def test_me(i)
542
+ puts sprintf(' The mass number of %-4s is %3s',
543
+ i,
544
+ CalculateAtomicMass.new(i).result.to_s
545
+ )
546
+ end
547
+ cliner {
548
+ e 'Nun berechnen wir einige Atomgewichte:'
549
+ ARRAY_TEST_THESE_MOLECULES.each {|entry| test_me(entry) }
550
+ }
551
+ e 'Das Atomgewicht von C12H12N2 ist: '
552
+ e ' → '+test_me('C12H12N2').to_s
553
+ else
554
+ _ = CalculateAtomicMass.new(ARGV)
555
+ end
556
+ end # mmasse T
557
+ # mmasse C16H12N2
558
+ # mmasse CH₃Cl
559
+ # mmasse CaCO3 --show-steps