※当サイトの記事には、広告・プロモーションが含まれます。

Rubyの「ブロック」の定義がハッキリしないし、メソッドの引数の種類が多過ぎて辛いんだが...

www.itmedia.co.jp

 ロシア発でドバイに拠点を置くTelegramは9月23日、法的な要請があればユーザーのIPアドレスと電話番号を当局に提供できるよう、プライバシーポリシーを改定したと発表した。

Telegram、違反者の個人情報を当局に提供するポリシー変更 - ITmedia NEWS

 Telegramは秘匿性の高さが特徴で、香港デモ参加者やウクライナ政府、ロシア政府を告発する個人なども安全な情報伝達手段として活用する半面、この秘匿性により、犯罪者が法執行機関の追跡を逃れるための連絡手段として使うことも多いと指摘されている。

Telegram、違反者の個人情報を当局に提供するポリシー変更 - ITmedia NEWS

 同社のパベル・ドゥーロフCEOは8月、犯罪目的の悪用を抑制する措置を講じなかったとして仏当局に逮捕された(現在は保釈中)。

Telegram、違反者の個人情報を当局に提供するポリシー変更 - ITmedia NEWS

 Telegramはポリシー変更に加え、検索機能を修正し、「問題のあるコンテンツはすべてアクセスできなくした」。

Telegram、違反者の個人情報を当局に提供するポリシー変更 - ITmedia NEWS

 この取り組みは「AIを活用する専任のモデレーターチーム」が実施したとしている。それでも安全でないコンテンツや違法なコンテンツを見つけた場合は、@SearchReportから報告できるようになった。

Telegram、違反者の個人情報を当局に提供するポリシー変更 - ITmedia NEWS

 Telegramは、「これらの対策により、犯罪者を思いとどまらせることができる」とし、「悪意ある人間が約10億人のユーザーのためのプラットフォームの完全性を危険にさらすことは許さない」と語った。

Telegram、違反者の個人情報を当局に提供するポリシー変更 - ITmedia NEWS

⇧ 問題のある内容かどうかの判断は、Telegram側ですべきではない気がするんだが...

IPアドレスや電話番号が提供されたとて、犯罪調査において、通話内容などが特定できないのであれば、仮に犯罪を行っていたとしても、法的に裁くことができないような...

悪意のある人間の抑制効果が無いような...

Rubyの「ブロック」の定義がハッキリしないし、メソッドの引数の種類が多過ぎて辛いんだが...

前に、

ts0818.hatenablog.com

Rubyのクラスについて触れたのだけど、「Oxidized」というライブラリで、

https://github.com/ytti/oxidized/blob/master/lib/oxidized/model/linuxgeneric.rb

class LinuxGeneric < Oxidized::Model
  using Refinements

  prompt /^(\w.*|\W.*)(:|#) /
  comment '# '

  # add a comment in the final conf
  def add_comment(comment)
    "\n###### #{comment} ######\n"
  end

  cmd :all do |cfg|
    cfg.gsub! /^(default (\S+).* (expires) ).*/, '\\1 <redacted>'
    cfg.cut_both
  end

  # show the persistent configuration
  pre do
    cfg = add_comment 'THE HOSTNAME'
    cfg += cmd 'cat /etc/hostname'

    cfg += add_comment 'THE HOSTS'
    cfg += cmd 'cat /etc/hosts'

    cfg += add_comment 'THE INTERFACES'
    cfg += cmd 'ip link'

    cfg += add_comment 'RESOLV.CONF'
    cfg += cmd 'cat /etc/resolv.conf'

    cfg += add_comment 'IP Routes'
    cfg += cmd 'ip route'

    cfg += add_comment 'IPv6 Routes'
    cfg += cmd 'ip -6 route'

    cfg += add_comment 'MOTD'
    cfg += cmd 'cat /etc/motd'

    cfg += add_comment 'PASSWD'
    cfg += cmd 'cat /etc/passwd'

    cfg += add_comment 'GROUP'
    cfg += cmd 'cat /etc/group'

    cfg += add_comment 'nsswitch.conf'
    cfg += cmd 'cat /etc/nsswitch.conf'

    cfg += add_comment 'VERSION'
    cfg += cmd 'cat /etc/issue'

    cfg
  end

  cfg :telnet do
    username /^Username:/
    password /^Password:/
  end

  cfg :telnet, :ssh do
    post_login do
      if vars(:enable) == true
        cmd "sudo su -", /^\[sudo\] password/
        cmd @node.auth[:password]
      elsif vars(:enable)
        cmd "su -", /^Password:/
        cmd vars(:enable)
      end
    end

    pre_logout do
      cmd "exit" if vars(:enable)
    end
    pre_logout 'exit'
  end
end    

⇧ 何と言うか、Javaに慣れてきた身からすると、見慣れない書きっぷりなのだが、

  cmd :all do |cfg|
    ...省略
  end  
  # show the persistent configuration
  pre do
    ...省略
  end  
  cfg :telnet do
    ...省略
  end  
  cfg :telnet, :ssh do
    ...省略
  end  
  pre_logout do
    ...省略
  end  

⇧ 見たことない構造のオンパレードで困りますと。

Rubyの公式のドキュメントによると、Rubyにおける「ブロック」とは、

docs.ruby-lang.org

ブロック付きメソッドとは制御構造の抽象化のために用いられるメソッドです。最初はループの抽象化のために用いられていたため、特にイテレータと呼ばれることもあります。 do ... end または { ... } で囲まれたコードの断片 (ブロックと呼ばれる)を後ろに付けてメソッドを呼び出すと、そのメソッドの内部からブロックを評価できます。ブロック付きメソッドを自分で定義するには yield 式を使います。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html#block

⇧ とありますと。

つまり、

do
  ...
end

⇧ 上記のような構造になっていることを、Rubyでは「ブロック」と見なすと。

で、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

⇧ なるほど、「メソッド」の「引数」の内、「&block」の部分が「ブロック」に該当するということらしい。

「ブロック」は「メソッド」の「引数」としても利用できると。

で、ややこしいのが、

   cmd :all do |cfg|
    cfg.gsub! /^(default (\S+).* (expires) ).*/, '\\1 '
    cfg.cut_both
  end

⇧ の部分で、cmdという「メソッド」の「引数」が、

No 引数 Rubyでの意味
1 :all シンボル
2 do |cfg| ~ end ブロック

の2つあるのだけど、その内の1つである「ブロック」内の

  • |cfg|

の部分が、「ブロック」処理における「引数」になるんだとか...

つまり、「ブロック」自体が、メソッドのように「引数」を受け取れるらしい。

もう、カオス過ぎるんだが...

とりあえず、Rubyでは、

  1. メソッド
  2. コンストラク
  3. ブロック

の3つで「引数」を渡すことができるっぽい。

何と言うか、

qiita.com

secret-garden.hatenablog.com

⇧ 上記サイト様によりますと、「引数」の種類がカオスなことになってるんだが...

Ruby、辛過ぎるんだが...

毎度モヤモヤ感が半端ない…

今回はこのへんで。