米Microsoftは、復活するスリーマイル島原子力発電所1号機の電力を独占購入する20年契約を、同発電所を保有する米Constellation Energyと結んだ。Constellationが9月20日(現地時間)に発表した。
Microsoftのエネルギー担当副社長、ボビー・ホリス氏はこの契約の発表文で「この契約は、カーボンネガティブを目指すわれわれの取り組みを支える、電力網の脱炭素化に向けた取り組みにおける大きな節目だ」と語った。
⇧ う~む...
「脱炭素化」の取組で「二酸化炭素の排出量の削減」に貢献しようとするのは良いのだが、「放射性廃棄物」の「処理問題」とかには目をつぶる感じなんかね...
まぁ、『何かを得るには、何かを失う』というような言葉もありますが、Microsoft側がやってることは問題を別の問題に転嫁させてるだけではありますな。
「脱炭素化」とか話題に上げずに、AIの活用に膨大な電力が必要な点だけ述べれば良かった気はしますな。
それか、「放射性廃棄物」の「処理問題」についても言及すべきですかね。
公表するのなら、
- 火力発電における問題
- 原子力発電における問題
どちらについての取組も明かすべきなんではという気がしますけど...
ちなみに、
⇧ 日本が魁て「火力発電」で「CO2を出さない」という取組を行っているそうな。
ただ、
- 火力発電
- 原子力発電
いずれも、埋蔵されている地下資源を元に発電しているからして、地下資源が枯渇したら継続できないのであって、人類がこの先どれだけ存続していくかは分かりませんが、「エネルギー問題」が解決できないと、「電力」を生み出せない時代が到来し、科学技術の発展も停滞していきそうではありますな。
まぁ、我々が生きている間は無用な心配とは思いますが...
とりあえず、明るくない未来に向かっていることは間違いないということになりますかね...
ちなみに、日本における「電気」の発祥は、
⇧ 1882年と記録されてるらしく、今が、2024年なので、142年が経過してますと。
エネルギーを生み出す地下資源が枯渇する時期は不明ですが、
⇧ エネルギーの消費量は、年々、右肩上がりではあるらしい。
いつか「電気」の無い時代が再来する日がやってくるということですかね。
単一責任の原則(Single Responsibility Principle)とは
Wikipediaによると、
単一責任の原則 (たんいつせきにんのげんそく、英: single-responsibility principle) は、プログラミングに関する原則であり、モジュール、クラスまたは関数は、単一の機能について責任を持ち、その機能をカプセル化するべきであるという原則である。モジュール、クラスまたは関数が提供するサービスは、その責任と一致している必要がある。
⇧ とありますと。
つまり、役割分担をしっかりしなさいよ、ってことなんだと思われますと。
例えば、
『あるデータを取得して、要件に沿って加工し、情報として保存する』
というような機能であれば、
- データを取得する
- データを加工し意味ある情報にする
- 保存する
の3つの大まかな処理に分けられるので、少なくとも3つのメソッドに分けられますと。
これを、1つのメソッドとかにしてしまうと、「単一責任の原則(Single Responsibility Principle)」に違反することになりますと。
勿論、3つのメソッドに分けた上で、3つのメソッドを利用する1つのメソッドを定義するのはありかと。(所謂、コンポーネント化って呼ばれる手法ですかね)
メソッドを分ける粒度が難しいところではありますが、ソースコードの可読性といった意味でも、分けられないかなと意識することは大事な気がしますと。
「単一責任の原則(Single Responsibility Principle)」は、
SOLID(ソリッド)は、ソフトウェア工学の用語であり、特にオブジェクト指向で用いられる五つの原則の頭字語である。ソフトウェア設計をより平易かつ柔軟にして保守しやすくすることを目的にしている。その特徴はインターフェースを仲介にしての機能の使用と、インターフェースによる機能の注入である。
この五つの原則は、アメリカのソフトウェア技術者ロバート・C・マーティンが提唱していた数々の設計原則の中からチョイスされたものである。マーティンが提唱していた原則は、例えば2000年に発表されたレポート『Design Principles and Design Patterns』の中で紹介されている。
そのうち五原則をSOLIDという語呂合わせの頭字語にして普及させたのは、ソフトウェア技術者マイケル・フェザーズであり、2004年以降に広く知られるようになった。SOLIDはオブジェクト指向設計由来であるが、アジャイルソフトウェア開発や適応的ソフトウェア開発といった方法論の哲学にもなっている。
五つの原則
SOLIDは、次の5つの原則からなる。
⇧「SOLID」の内の1つになりますと。
単一責任の原則(Single Responsibility Principle)に反してるのはOxidizedの問題なのかRubyの問題なのか
で、ネットワーク機器の設定情報をバックアップする「Oxidized」というライブラリがあるのだけど、ちょっと、ソースコードが分かり辛い。
Ruby初学者であるからなのかもしれませんが...
■https://github.com/ytti/oxidized/blob/master/lib/oxidized/model/model.rb
require 'strscan' require_relative 'outputs' module Oxidized class Model using Refinements include Oxidized::Config::Vars class << self def inherited(klass) super if klass.superclass == Oxidized::Model klass.instance_variable_set '@cmd', (Hash.new { |h, k| h[k] = [] }) klass.instance_variable_set '@cfg', (Hash.new { |h, k| h[k] = [] }) klass.instance_variable_set '@procs', (Hash.new { |h, k| h[k] = [] }) klass.instance_variable_set '@expect', [] klass.instance_variable_set '@comment', nil klass.instance_variable_set '@prompt', nil else # we're subclassing some existing model, take its variables instance_variables.each do |var| iv = instance_variable_get(var) klass.instance_variable_set var, iv.dup @cmd[:cmd] = iv[:cmd].dup if var.to_s == "@cmd" end end end def comment(str = "# ") @comment = if block_given? yield elsif not @comment str else @comment end end def prompt(regex = nil) @prompt = regex || @prompt end def cfg(*methods, **args, &block) [methods].flatten.each do |method| process_args_block(@cfg[method.to_s], args, block) end end def cfgs @cfg end def cmd(cmd_arg = nil, **args, &block) if cmd_arg.instance_of?(Symbol) process_args_block(@cmd[cmd_arg], args, block) else process_args_block(@cmd[:cmd], args, [cmd_arg, block]) end Oxidized.logger.debug "lib/oxidized/model/model.rb Added #{cmd_arg} to the commands list" end def cmds @cmd end def expect(regex, **args, &block) process_args_block(@expect, args, [regex, block]) end def expects @expect end # calls the block at the end of the model, prepending the output of the # block to the output string # # @author Saku Ytti <saku@ytti.fi> # @since 0.0.39 # @yield expects block which should return [String] # @return [void] def pre(**args, &block) process_args_block(@procs[:pre], args, block) end # calls the block at the end of the model, adding the output of the block # to the output string # # @author Saku Ytti <saku@ytti.fi> # @since 0.0.39 # @yield expects block which should return [String] # @return [void] def post(**args, &block) process_args_block(@procs[:post], args, block) end # @author Saku Ytti <saku@ytti.fi> # @since 0.0.39 # @return [Hash] hash proc procs :pre+:post to be prepended/postfixed to output attr_reader :procs private def process_args_block(target, args, block) if args[:clear] if block.instance_of?(Array) target.reject! { |k, _| k == block[0] } target.push(block) else target.replace([block]) end else method = args[:prepend] ? :unshift : :push target.send(method, block) end end end attr_accessor :input, :node def cmd(string, &block) Oxidized.logger.debug "lib/oxidized/model/model.rb Executing #{string}" out = @input.cmd(string) return false unless out out = out.b unless Oxidized.config.input.utf8_encoded? self.class.cmds[:all].each do |all_block| out = instance_exec out, string, &all_block end if vars :remove_secret self.class.cmds[:secret].each do |all_block| out = instance_exec out, string, &all_block end end out = instance_exec out, &block if block process_cmd_output out, string end def output @input.output end def send(data) @input.send data end def expect(...) self.class.expect(...) end def cfg self.class.cfgs end def prompt self.class.prompt end def expects(data) self.class.expects.each do |re, cb| if data.match re data = cb.arity == 2 ? instance_exec([data, re], &cb) : instance_exec(data, &cb) end end data end def get Oxidized.logger.debug 'lib/oxidized/model/model.rb Collecting commands\' outputs' outputs = Outputs.new procs = self.class.procs self.class.cmds[:cmd].each do |command, block| out = cmd command, &block return false unless out outputs << out end procs[:pre].each do |pre_proc| outputs.unshift process_cmd_output(instance_eval(&pre_proc), '') end procs[:post].each do |post_proc| outputs << process_cmd_output(instance_eval(&post_proc), '') end outputs end def comment(str) data = '' str.each_line do |line| data << self.class.comment << line end data end def xmlcomment(str) # XML Comments start with <!-- and end with --> # # Because it's illegal for the first or last characters of a comment # to be a -, i.e. <!--- or ---> are illegal, and also to improve # readability, we add extra spaces after and before the beginning # and end of comment markers. # # Also, XML Comments must not contain --. So we put a space between # any double hyphens, by replacing any - that is followed by another - # with '- ' data = '' str.each_line do |_line| data << '<!-- ' << str.gsub(/-(?=-)/, '- ').chomp << " -->\n" end data end def screenscrape @input.class.to_s.match(/Telnet/) || vars(:ssh_no_exec) end private def process_cmd_output(output, name) output = String.new('') unless output.instance_of?(String) output.process_cmd(name) output end end end
⇧ 例えば、上記のクラスの灰色に塗りつぶした部分の120行目~136行目のメソッドは、
- 引数1(文字列)、引数2(ブロック)を受け取り、引数1(文字列)のコマンドを実行する
- 1の処理の結果を、引数2(ブロック)の引数部分に渡して引数2(ブロック)の処理を実行する
- 2の処理の結果を、加工する
- 戻り値を返す
という感じで、1つのメソッドに処理を盛り込み過ぎな感じがありますと。
この初見殺しっぽいソースコードの構成が、
- Ruby特有の言語の仕様のせいなのか
- Oxidizedの実装の問題なのか
分からないのですが、明らかに、「単一責任の原則(Single Responsibility Principle)に反して」に反していそうですと。
Rubyの「ブロック」という仕様のせいだと思うのだけど、素直に、メソッドを分解すれば良いような気がするんだが、Rubyだと、1つのメソッドで複数の処理を行うのが一般的なんですかね?
しかも、メソッドを利用している部分を確認したところ、
■https://github.com/ytti/oxidized/blob/master/lib/oxidized/model/ios.rb
class IOS < Oxidized::Model using Refinements prompt /^([\w.@()-]+[#>]\s?)$/ comment '! ' # example how to handle pager # expect /^\s--More--\s+.*$/ do |data, re| # send ' ' # data.sub re, '' # end # non-preferred way to handle additional PW prompt # expect /^[\w.]+>$/ do |data| # send "enable\n" # send vars(:enable) + "\n" # data # end cmd :all do |cfg| # cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager # cfg.gsub! /\cH+/, '' # example how to handle pager # get rid of errors for commands that don't work on some devices cfg.gsub! /^% Invalid input detected at '\^' marker\.$|^\s+\^$/, '' cfg.cut_both end cmd :secret do |cfg| cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' cfg.gsub! /^(snmp-server host \S+( vrf \S+)?( informs?)?( version (1|2c|3 (noauth|auth|priv)))?)\s+\S+((\s+\S*)*)\s*/, '\\1 <secret hidden> \\7' cfg.gsub! /^(username .+ (password|secret) \d) .+/, '\\1 <secret hidden>' cfg.gsub! /^(enable (password|secret)( level \d+)? \d) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+(?:password|secret)) (?:\d )?\S+/, '\\1 <secret hidden>' cfg.gsub! /^(.*wpa-psk ascii \d) (\S+)/, '\\1 <secret hidden>' cfg.gsub! /^(.*key 7) (\d.+)/, '\\1 <secret hidden>' cfg.gsub! /^(tacacs-server (.+ )?key) .+/, '\\1 <secret hidden>' cfg.gsub! /^(crypto isakmp key) (\S+) (.*)/, '\\1 <secret hidden> \\3' cfg.gsub! /^(\s+ip ospf message-digest-key \d+ md5) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+ip ospf authentication-key) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+neighbor \S+ password) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+vrrp \d+ authentication text) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+standby \d+ authentication) .{1,8}$/, '\\1 <secret hidden>' cfg.gsub! /^(\s+standby \d+ authentication md5 key-string) .+?( timeout \d+)?$/, '\\1 <secret hidden> \\2' cfg.gsub! /^(\s+key-string) .+/, '\\1 <secret hidden>' cfg.gsub! /^((tacacs|radius) server [^\n]+\n(\s+[^\n]+\n)*\s+key) [^\n]+$/m, '\1 <secret hidden>' cfg.gsub! /^(\s+ppp (chap|pap) password \d) .+/, '\\1 <secret hidden>' cfg end cmd 'show version' do |cfg| comments = [] comments << cfg.lines.first lines = cfg.lines lines.each_with_index do |line, i| slave = '' slaveslot = '' if line =~ /^Slave in slot (\d+) is running/ slave = " Slave:" slaveslot = ", slot #{Regexp.last_match(1)}" end comments << "Image:#{slave} Compiled: #{Regexp.last_match(1)}" if line =~ /^Compiled (.*)$/ comments << "Image:#{slave} Software: #{Regexp.last_match(1)}, #{Regexp.last_match(2)}" if line =~ /^(?:Cisco )?IOS .* Software,? \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ comments << "ROM Bootstrap: #{Regexp.last_match(3)}" if line =~ /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ comments << "BOOTFLASH: #{Regexp.last_match(1)}" if line =~ /^BOOTFLASH: .*(Version.*)$/ comments << "Memory: nvram #{Regexp.last_match(1)}" if line =~ /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ comments << "Memory: flash #{Regexp.last_match(1)}" if line =~ /^(\d+[kK]) bytes of (flash memory|flash internal|processor board System flash|ATA CompactFlash)/i comments << "Memory: pcmcia #{Regexp.last_match(2)} #{Regexp.last_match(3)}#{Regexp.last_match(4)} #{Regexp.last_match(1)}" if line =~ /^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i if line =~ /(\S+(?:\sseries)?)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i sproc = Regexp.last_match(1) cpu = Regexp.last_match(2) mem = Regexp.last_match(3) cpuxtra = '' comments << "Chassis type:#{slave} #{sproc}" comments << "Memory:#{slave} main #{mem}" # check the next two lines for more CPU info comments << "Processor ID: #{Regexp.last_match(1)}" if cfg.lines[i + 1] =~ /processor board id (\S+)/i if cfg.lines[i + 2] =~ /(cpu at |processor: |#{cpu} processor,)/i # change implementation to impl and prepend comma cpuxtra = cfg.lines[i + 2].gsub("implementation", 'impl').gsub(/^/, ', ').chomp end comments << "CPU:#{slave} #{cpu}#{cpuxtra}#{slaveslot}" end comments << "Image: #{Regexp.last_match(1)}" if line =~ /^System image file is "([^"]*)"$/ end comments << "\n" comment comments.join "\n" end cmd 'show vtp status' do |cfg| cfg.gsub! /^$\n/, '' cfg.gsub! /Configuration last modified by.*\n/, '' cfg.gsub! /^/, 'VTP: ' unless cfg.empty? comment "#{cfg}\n" end cmd 'show inventory' do |cfg| comment cfg end post do cmd_line = 'show running-config' cmd_line += ' view full' if vars(:ios_rbac) cmd cmd_line do |cfg| cfg = cfg.each_line.to_a[3..-1] cfg = cfg.reject { |line| line.match /^ntp clock-period / }.join cfg = cfg.each_line.reject { |line| line.match /^! (Last|No) configuration change (at|since).*/ unless line =~ /\d+\sby\s\S+$/ }.join cfg.gsub! /^Current configuration : [^\n]*\n/, '' cfg.gsub! /^ tunnel mpls traffic-eng bandwidth[^\n]*\n*( (?: [^\n]*\n*)* tunnel mpls traffic-eng auto-bw)/mx, '\1' cfg end end cfg :telnet do username /^Username:/i password /^Password:/i end cfg :telnet, :ssh do # preferred way to handle additional passwords post_login do if vars(:enable) == true cmd "enable" elsif vars(:enable) cmd "enable", /^[pP]assword:/ cmd vars(:enable) end end post_login 'terminal length 0' post_login 'terminal width 0' pre_logout 'exit' end end
⇧ いずれも、戻り値をガン無視しとるように見えるんだが...
え~っと...
発狂しそうなんだが...
いや、Ruby、意味が分からな過ぎる...
と言うか、
⇧ return省略しなくても良くない?
returnの6文字を省略するぐらいなら、省略せずに書いたら駄目なの?
最早、ツッコミどころが多過ぎるのと、何がしたいのか全く分からないのとで、頭抱えるしかないんだが...
何か、普通に、
■model/helper/custom_ios_helper.rb
class CustomIOSHelper ################################################################ # ? # @param cfg コマンド実行結果の文字列 # @return cfg 文字列 ################################################################ def self.take_all_info(cfg) # cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager # cfg.gsub! /\cH+/, '' # example how to handle pager # get rid of errors for commands that don't work on some devices cfg.gsub! /^% Invalid input detected at '\^' marker\.$|^\s+\^$/, '' return cfg end ################################################################ # 機密情報をマスクする処理 # @param cfg コマンド実行結果の文字列 # @return cfg 機密情報をマスクする処理実施後の文字列 ################################################################ def self.secret_hidden(cfg) cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>' cfg.gsub! /^(snmp-server host \S+( vrf \S+)?( informs?)?( version (1|2c|3 (noauth|auth|priv)))?)\s+\S+((\s+\S*)*)\s*/, '\\1 <secret hidden> \\7' cfg.gsub! /^(username .+ (password|secret) \d) .+/, '\\1 <secret hidden>' cfg.gsub! /^(enable (password|secret)( level \d+)? \d) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+(?:password|secret)) (?:\d )?\S+/, '\\1 <secret hidden>' cfg.gsub! /^(.*wpa-psk ascii \d) (\S+)/, '\\1 <secret hidden>' cfg.gsub! /^(.*key 7) (\d.+)/, '\\1 <secret hidden>' cfg.gsub! /^(tacacs-server (.+ )?key) .+/, '\\1 <secret hidden>' cfg.gsub! /^(crypto isakmp key) (\S+) (.*)/, '\\1 <secret hidden> \\3' cfg.gsub! /^(\s+ip ospf message-digest-key \d+ md5) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+ip ospf authentication-key) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+neighbor \S+ password) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+vrrp \d+ authentication text) .+/, '\\1 <secret hidden>' cfg.gsub! /^(\s+standby \d+ authentication) .{1,8}$/, '\\1 <secret hidden>' cfg.gsub! /^(\s+standby \d+ authentication md5 key-string) .+?( timeout \d+)?$/, '\\1 <secret hidden> \\2' cfg.gsub! /^(\s+key-string) .+/, '\\1 <secret hidden>' cfg.gsub! /^((tacacs|radius) server [^\n]+\n(\s+[^\n]+\n)*\s+key) [^\n]+$/m, '\1 <secret hidden>' cfg.gsub! /^(\s+ppp (chap|pap) password \d) .+/, '\\1 <secret hidden>' return cfg end ################################################################ # 対象機器から取得した情報を加工する処理 # @param cfg コマンド実行結果の文字列 # @return comments 加工後の文字列の配列 ################################################################ def self.take_machine_info(cfg) comments = [] comments << cfg.lines.first lines = cfg.lines lines.each_with_index do |line, i| slave = '' slaveslot = '' if line =~ /^Slave in slot (\d+) is running/ slave = " Slave:" slaveslot = ", slot #{Regexp.last_match(1)}" end comments << "Image:#{slave} Compiled: #{Regexp.last_match(1)}" if line =~ /^Compiled (.*)$/ comments << "Image:#{slave} Software: #{Regexp.last_match(1)}, #{Regexp.last_match(2)}" if line =~ /^(?:Cisco )?IOS .* Software,? \(([A-Za-z0-9_-]*)\), .*Version\s+(.*)$/ comments << "ROM Bootstrap: #{Regexp.last_match(3)}" if line =~ /^ROM: (IOS \S+ )?(System )?Bootstrap.*(Version.*)$/ comments << "BOOTFLASH: #{Regexp.last_match(1)}" if line =~ /^BOOTFLASH: .*(Version.*)$/ comments << "Memory: nvram #{Regexp.last_match(1)}" if line =~ /^(\d+[kK]) bytes of (non-volatile|NVRAM)/ comments << "Memory: flash #{Regexp.last_match(1)}" if line =~ /^(\d+[kK]) bytes of (flash memory|flash internal|processor board System flash|ATA CompactFlash)/i comments << "Memory: pcmcia #{Regexp.last_match(2)} #{Regexp.last_match(3)}#{Regexp.last_match(4)} #{Regexp.last_match(1)}" if line =~ /^(\d+[kK]) bytes of (Flash|ATA)?.*PCMCIA .*(slot|disk) ?(\d)/i if line =~ /(\S+(?:\sseries)?)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i sproc = Regexp.last_match(1) cpu = Regexp.last_match(2) mem = Regexp.last_match(3) cpuxtra = '' comments << "Chassis type:#{slave} #{sproc}" comments << "Memory:#{slave} main #{mem}" # check the next two lines for more CPU info comments << "Processor ID: #{Regexp.last_match(1)}" if cfg.lines[i + 1] =~ /processor board id (\S+)/i if cfg.lines[i + 2] =~ /(cpu at |processor: |#{cpu} processor,)/i # change implementation to impl and prepend comma cpuxtra = cfg.lines[i + 2].gsub("implementation", 'impl').gsub(/^/, ', ').chomp end comments << "CPU:#{slave} #{cpu}#{cpuxtra}#{slaveslot}" end comments << "Image: #{Regexp.last_match(1)}" if line =~ /^System image file is "([^"]*)"$/ end comments << "\n" return comments.join "\n" end ################################################################ # 対象機器から取得した設定情報を加工する処理 # @param cfg コマンド実行結果の文字列 # @return comments 加工後の文字列 ################################################################ def self.take_machine_config_info(cfg) cfg = cfg.each_line.to_a[3..-1] cfg = cfg.reject { |line| line.match /^ntp clock-period / }.join cfg = cfg.each_line.reject { |line| line.match /^! (Last|No) configuration change (at|since).*/ unless line =~ /\d+\sby\s\S+$/ }.join cfg.gsub! /^Current configuration : [^\n]*\n/, '' cfg.gsub! /^ tunnel mpls traffic-eng bandwidth[^\n]*\n*( (?: [^\n]*\n*)* tunnel mpls traffic-eng auto-bw)/mx, '\1' return cfg end end
■model/custom_ios.rb
require_relative 'custom_ios_helper' class CustomIOS < Oxidized::Model using Refinements prompt /^([\w.@()-]+[#>]\s?)$/ comment '! ' cmd :all do |cfg| cfg = CustomIOSHelper.take_all_info(cfg) cfg.cut_both end cmd :secret do |cfg| # 機密情報をマスクする cfg = CustomIOSHelper.secret_hidden(cfg) return cfg end cmd 'show version' do |cfg| # 対象機器の情報を comment = CustomIOSHelper.take_machine_info(cfg) end cmd 'show inventory' do |cfg| comment cfg end post do cmd_line = 'show running-config' cmd_line += ' view full' if vars(:ios_rbac) cmd cmd_line do |cfg| cfg = CustomIOSHelper.take_machine_config_info return cfg end end cfg :telnet do username /^Username:/i password /^Password:/i end cfg :telnet, :ssh do # preferred way to handle additional passwords post_login do if vars(:enable) == true cmd "enable" elsif vars(:enable) cmd "enable", /^[pP]assword:/ cmd vars(:enable) end end post_login 'terminal length 0' post_login 'terminal width 0' pre_logout 'exit' end end
みたいに分離してしまえば良いような気がするんだが。
テストとかもし易くなるしで、個人的には分離してしまいたい派なんだが、Rubyだと処理を分離するのは御法度なのかね?
まぁ、
の区別が付き辛いので、分離がし辛いのかもしらんけど...
驚きなのが、
という感じで、知っていないと区別できなくない?っていう感じで、カオスの極致過ぎるんだわ...
他に、メソッドの区別が分かり辛過ぎて、分離が困難を極めますと...
冗談抜きで、Ruby、ストレスでしかなくて地獄なんだが...
Rubyカオス過ぎる説について「異論は認めない」と言ったとて、過言ではない気がしてしまうんだが...
たまたま、「Oxidized」のソースコードが酷過ぎただけなのか、Ruby全体のソースコードも同様な状況なのか、Rubyの思想が分からな過ぎるのだが、ソースコードのお手本が欲しい...
ちなみに、メソッドで戻り値が無い場合、所謂、JavaのvoidのようなことをRubyで実装する場合、どうすれば良いのか?
⇧ 上記サイト様がまとめて下さっておりました。
うむ、Ruby、カオスだわ...
毎度モヤモヤ感が半端ない…
今回はこのへんで。