cocoapods源码的ruby 语法学习

Cache < Command 继承

image.png

https://www.cnblogs.com/tardis/p/4004438.html 更多继承

  • 有时, 我们希望子类从父类继承来的方法可以做与父类不相同的事情,这就需要在子类中重写方法。例如, 你有一个类名字叫Email继承于类Message,两个类都有send方法,但是Email类的send方法需要有邮件地址和一系列邮件协议,但是Message中的send方法并不知道这些,与其在Email类中添加send_mail方法,而从父类继承的send方法弃之不用, 不如显式的修改send方法以适应Email的需求。

  • 另一方面, 有时子类发现它所需要的继承自父类的方法已经被改写, 不要惊慌, 我们可以直接获取父类的响应方法, 这需要使用super关键字。

  • 当你在方法中调用super, 这就是告诉Ruby,在父类中找到与调用super的这个方法同名的函数,如果找到, 那么Ruby将会使用其父类版本的这个方法。

:: 语法

@cache = Downloader::Cache.new(Config.instance.cache_root + 'Pods')

你可以通过在方法名称前加上类或模块名称和 . 来调用类或模块中的方法。你可以使用类或模块名称和两个冒号 :: 来引用类或模块中的常量。

:: 是一元运算符,允许在类或模块内定义常量、实例方法和类方法,可以从类或模块外的任何地方进行访问。

请记住:在 Ruby 中,类和方法也可以被当作常量。

多行字符串

https://www.runoob.com/ruby/ruby-syntax.html

#!/usr/bin/ruby -w
# -*- coding : utf-8 -*-
 
print <
        <<-EOS
### Installation Source

  ```/
Executable Path: #{actual_path}
  ```/
EOS

返回值

https://www.runoob.com/ruby/ruby-method.html
Ruby 中的每个方法默认都会返回一个值。这个返回的值是最后一个语句的值。例如:

   def actual_path
        $PROGRAM_NAME
    end

Ruby语法解释:attr_reader,attr_writer和attr_accessor

解释

变量set 和get

    attr_accessor :required
    alias_method :required?, :required

    # @return [Boolean]
    #         Indicates if the argument is repeatable (= can appear multiple
    #         times in the command, which is indicated by '...' in the banner)
    #
    attr_accessor :repeatable
attr_accessor :abc
等同于
def abc
return @abc
end
def abc=(abc)
@abc = abc
end

ruby中的alias和alias_method

new_name 和old_name

image.png

(12)alias :new_name :old_name 可以用来给方法取别名。alias是个关键字,和他类似的还有一个Module#alias_method方法
https://blog.csdn.net/raosheng1993/article/details/45458821 的第12点

if 语法

https://haicoder.net/ruby/ruby-else.html 这里面有所有的if语法记录

  message = verbose_prefix + message if config.verbose?
        puts_indented message if config.verbose?

如果 if 语句条件为真,则会执行相对应的代码

#!/usr/bin/ruby -w
# -*- coding : utf-8 -*-
puts "HaiCoder(www.haicoder.net)"
$debug=1
print "debug\n" if $debug

程序运行后,控制台输出如下:

image.png

因为 debug 变量为 1,所以我们这里输出了 debug。

Ruby if修饰符总结

在 Ruby 中,if 修饰词组表示当 if 右边之条件成立时才执行 if 左边的式子。即如果 conditional 为真,则执行 code。

:语法

冒号:
https://www.jianshu.com/p/28d7f3a17b29

  # spec.authors            = { "#{data[:author_name]}" => "#{data[:author_email]}" }
 def pod(set, mode = :normal)
        if mode == :name_and_version
          puts_indented "#{set.name} #{set.versions.first.version}"
        else

当我说{ :bla => 1, :bloop => 2 }时,:到底是做什么的?我在某个地方读到过关于它是如何类似于一个字符串,但不知怎的是一个符号.

:foo是一个名为"foo"的符号.符号有一个明显的特点,即任何两个命名相同的符号都是相同的:

"foo".equal? "foo"  # false
:foo.equal? :foo    # true

这使得比较两个符号的速度非常快(因为只涉及指针比较,而不是像比较字符串中的所有字符那样),而且不会有大量相同符号的副本.

此外,与字符串不同,符号是不可变的.

unless 用法

          help! 'A Podfile path is required.' unless @path

https://haicoder.net/ruby/ruby-unless.html

Ruby 中,unless 语句和 if 语句作用相反,即如果 conditional 为假,则执行 code。如果 conditional 为真,则执行 else 子句中指定的 code。
Ruby unless语句详解
语法

unless conditional [then]
   code
[else
   code ]
end

include ProjectDirectory 用法

image.png
      unless repl_command == '\n'
  def execute_repl_command(repl_command)
          unless repl_command == '\n'
            repl_commands = repl_command.split
            subcommand = repl_commands.shift.capitalize
            arguments = repl_commands
            subcommand_class = Pod::Command::IPC.const_get(subcommand)
            subcommand_class.new(CLAide::ARGV.new(arguments)).run
            signal_end_of_output
          end
        end

concat(super)

  def self.options
          [
            ['--template-url=URL', 'The URL of the git repo containing a compatible template'],
          ].concat(super)
        end
    private

用法

ensure 关键字

image.png

当一个方法结束工作时我们也许需要进行清理工作.也许一个打开的文件需要关闭,缓冲区的数据应清空等等.如果对于每一个方法这里永远只有一个退出点,我们可以心安理得地将我们的清理代码放在一个地方并知道它会被执行;但一个方法可能从多个地方返回,或者因为异常我们的清理代码被意外跳过.

使用 ensure 语句
有时候,无论是否抛出异常,您需要保证一些处理在代码块结束时完成。例如,您可能在进入时打开了一个文件,当您退出块时,您需要确保关闭文件。

ensure 子句做的就是这个。ensure 放在最后一个 rescue 子句后,并包含一个块终止时总是执行的代码块。它与块是否正常退出、是否抛出并处理异常、是否因一个未捕获的异常而终止,这些都没关系,ensure 块始终都会运行。
https://www.runoob.com/ruby/ruby-exceptions.html

yield if block_given?

image.png
      from_path = config.podfile_path.dirname if config.podfile_path
   if pathname
          from_path = config.podfile_path.dirname if config.podfile_path
          from_path ||= Pathname.pwd
          path = begin
                   Pathname(pathname).relative_path_from(from_path)
                 rescue
                   pathname
                 end
          "`#{path}`"
        else

https://juejin.cn/post/6844903683524673550 讲了block的回调

private

https://blog.csdn.net/qq284489030/article/details/88369791

总结一下

public方法可以被定义它的类和子类访问,并可以被类和子类的实例对象调用;
protected方法可以被定义它的类和子类访问,不能被类和子类的实例对象调用,但可以被该类和子类的实例对象(所有)访问;
private方法可以被定义它的类和子类访问,不能被类和子类的实例对象调用,且实例对象只能访问自己的private方法。

问号

       def repo_update?(default: false)
          if @repo_update.nil?
            default
          else
            @repo_update
          end
        end

        def initialize(argv)
          @repo_update = argv.flag?('repo-update')
          super
        end

在Ruby中有很多方法是以?和!号结尾的

“?”被用于标示谓词,即返回Boolean直的方法,如Array.empty?(判断数组中元素是否为空)

“!”出现在方法名尾部的感叹号表明使用该方法是需要多加小心。许多Ruby的核心类都定义了

成对的方法,它们具有同样的名称,只是结尾相差一个“!”,通常情况下,不带感叹号的方法返

调用该方法的一个拷贝,二带感叹号的方法则是一个可变方法,该方法会修改原来的对象,如Array

类中的sort和sort!

ruby中的方法可以以问号和叹号结尾,问号通常用于谓语方法,这种方法返回一个布尔值。例如array和hash类都定义了一个empty?方法,这个方法用于测试数据结构中有没有元素。

如果方法以叹号结尾,这意味着我们在使用这个方法的时候要小心,比如大多数核心的ruby类库方法都提供两个同名的方法,一个以叹号结尾,一个没有,

区别在于,如果使用没有叹号结尾的方法,你在调用它的时候会得到当前对象的一个拷贝而不会修改原始对象,而如果使用带有叹号的方法,你在调用它的时候会直接修改当前对象的值。

叹号 !

2.以感叹号结尾的方法。一般表示这是危险的,或者会修改接收者对象的方法。

def insert_sort!
    (0...self.length).to_a.each do |j|
      key = self[j]
      i = j - 1;
      while i >= 0 and self[i] > key
        self[i+1] = self[i]
        i = i-1
      end
      self[i+1] = key
    end
    self
  end`

运行上述代码之后,会对传入的数据进行排序,修改了(接收者)对象。
Ruby核心类都定义了成对的方法,它们有同样的名字,彼此的差别在于其中一个以感叹号结尾,而另一个没有,通常情况下,不带感叹号的方法返回调用该方法的对象的一个修改过的拷贝,而带感叹号的方法则是一个可变的方法,该方法会修改原对象。

3.以等号结尾的方法。一般被赋值的方法以等号结尾。

def validate!

def validate!

<<

     ``` section << " (branch `#{@branch}`)" if @branch```

方法传参 (关键字参数)

7.3.4 关键字参数

https://www.kancloud.cn/imxieke/ruby-base/107294

关键字参数是 Ruby 2.0 中的新特性。

在目前为止介绍过的方法定义中,我们都需要定义调用方法时的参数个数以及调用顺序。而使用关键字参数,就可以将参数名与参数值成对地传给方法内部使用。

使用关键字参数定义方法的语法如下所示:

def 方法名(参数 1: 参数 1 的值, 参数 2: 参数 2 的值, …)
 希望执行的处理
end

除了参数名外,使用“参数名 : 值”这样的形式还可以指定参数的默认值。用关键字参数改写计算立方体表面积的 area 方法的程序如下所示:

def area2(x: 0, y: 0, z: 0)
  xy = x * y
  yz = y * z
  zx = z * x
  (xy + yz + zx ) * 2
end

p area2(x: 2, y: 3, z: 4)    #=> 52
p area2(z: 4, y: 3, x: 2)    #=> 52 (改变参数的顺序)
p area2(x: 2, z: 3)          #=> 12 (省略y)

这个方法有参数 x、y、z,各自的默认值都为 0。调用该方法时,可以像 x: 2 这样,指定一对实际的参数名和值。在用关键字参数定义的方法中,每个参数都指定了默认值,因此可以省略任何一个。而且,由于调用方法时也会把参数名传给方法,所以参数顺序可以自由地更改。

不过,如果把未定义的参数名传给方法,程序就会报错,如下所示:

area2(foo: 0) #=> 错误:unknown keyword: foo(ArgumentError)
为了避免调用方法时因指定了未定义的参数而报错,我们可以使用“** 变量名”的形式来 接收未定义的参数。下面这个例子的方法中,除了关键字参数 x、y、z 外,还定义了 **arg 参数。参数 arg 会把参数列表以外的关键字参数以散列对象的形式保存。

def meth(x: 0, y: 0, z: 0, **args)
  [x, y, z, args]
end

p meth(z: 4, y: 3, x: 2)        #=> [2, 3, 4, {}]
p meth(x: 2, z: 3, v: 4, w: 5)  #=> [2, 0, 3, {:v=>4, :w=>5}]

关键字参数与普通参数的搭配使用

关键字参数可以与普通参数搭配使用。

def func(a, b: 1, c:2)
  ┊
end

上述这样定义时,a 为必须指定的普通参数,b、c 为关键字参数。调用该方法时,可以像下面这样,首先指定普通参数,然后是关键字参数。

func(1, b: 2, c: 3)

用散列传递参数

调用用关键字参数定义的方法时,可以使用以符号作为键的散列来传递参数。这样一来,程序就会检查散列的键与定义的参数名是否一致,并将与散列的键一致的参数名传递给方法。

def area2(x: 0, y: 0, z: 0)
  xy = x * y
  yz = y * z
  zx = z * x
  (xy + yz + zx ) * 2
end
 
args1 = {x: 2, y: 3, z: 4}
p area2(args1)            #=> 52
 
args2 = {x: 2, z: 3}      #=> 省略y
p area2(args2)            #=> 12

方法调用

            branch_name, = Executable.capture_command('git', %w(name-rev --name-only HEAD), :capture => :out, :chdir => source.repo)

方法定义

    def self.capture_command(executable, command, capture: :merge, env: {}, **kwargs)
      bin = which!(executable)

      require 'open3'
      command = command.map(&:to_s)
      case capture
      when :merge then Open3.capture2e(env, [bin, bin], *command, **kwargs)
      when :both then Open3.capture3(env, [bin, bin], *command, **kwargs)
      when :out then Open3.capture3(env, [bin, bin], *command, **kwargs).values_at(0, -1)
      when :err then Open3.capture3(env, [bin, bin], *command, **kwargs).drop(1)
      when :none then Open3.capture3(env, [bin, bin], *command, **kwargs).last
      end
    end
image.png

箭头 向左, 向右

Ruby语言的非操作符(Nonoperator)和操作符(Operator)
https://www.huoxiaoqiang.com/ruby/rubylang/1516.html

1.<<  和  >>代表左移或右移

puts  1<<2   

输出结果为:4 

代表1的二进制向左移动4位,即x<>

git!(%W(-C #{dir} pull))

https://www.delftstack.com/zh/howto/ruby/ruby-what-does-w-mean/
array = ["one", "two", "three"]
输出:
["one", "two", "three"]
它有效,但输入引号和逗号需要花费大量时间和精力。Ruby 为我们提供了更优雅的解决方案。

%w 语法用于创建字符串数组,而不需要在每个元素之间使用逗号或引号。

每个元素都将被视为一个字符串,并应以空格分隔。
array = %w[1 two 3.4 [] {}]
输出:
["1", "two", "3.4", "[]", "{}"]

if path =~ %r{https?://}

   @podspecs_paths.each do |path|
              if path =~ %r{https?://}
                require 'cocoapods/open-uri'
                output_path = podspecs_tmp_dir + File.basename(path)

=~ 是正则表达式
https://www.runoob.com/ruby/ruby-regular-expressions.html

正则表达式是一种特殊序列的字符,它通过使用有专门语法的模式来匹配或查找字符串集合。

<<

            files << (pathname = Pathname.new(path))
  • 1.<< 和 >>代表左移或右移

    puts 1<<2

    输出结果为:4

    代表1的二进制向左移动4位,即x<2*y。平时用不到这种方法

  • 2.字符串拼接

    test = "you"

    txt = "sb"

    p test<

    输出结果为:yousb

  • 3.数组添加元素

    ar = Array.new

    ar<<3

    p ar

    输出结果为:[3]

**字符串拼接和数组添加元素不能使用>>

reject的用法

    ].concat(super).reject { |(name, _)| name == '--no-repo-update' }

reject和reject!
reject返回不满足代码块的元素数组
reject!删除数组中满足代码块的元素

a=[1,2,3,5]
a.reject! {|x| x<4}
p a #[5]

b = [1,2,3,4,5]
c = b.reject {|x| x>4}
p c
p b
[1, 2, 3, 4]
[1, 2, 3, 4, 5]

||= 的符号

    @lockfile ||= begin

https://blog.csdn.net/lihuan974683978/article/details/8686297

a||=123
就是 当a存在但是没有赋值时 a=123

extend 关键字

extend:在定义类时使用,把module的实例方法作为当前类的类方法.

module Test

 def class_type

  "This class is of type:#{self.class}"

 end

end

class TestClass

 extend Test

end


puts TestClass.class_type  #=>  This class is of type:Class
module Pod
  class Command
    class Repo < Command
      self.abstract_command = true

      # @todo should not show a usage banner!
      #
      self.summary = 'Manage spec-repositories'
      self.default_subcommand = 'list'

      #-----------------------------------------------------------------------#

      extend Executable
      executable :git

      def dir
        config.repos_dir + @name
      end
    end
  end
end

=> 箭头函数

=>将键与哈希映射文字中的值分开。它不可重载,也没有专门连接到符号。

哈希图文字的形式为{key1 => value1, key2 => value2, ...},但是当用作函数的最后一个参数时,可以省略花括号。因此,当您看到类似f(:a => 1, :b => 2)的函数调用时,将使用一个参数调用f,这是一个具有键:a和:b以及值1和2的哈希映射。

def pre_download(sandbox)
        title = "Pre-downloading: `#{name}` #{description}"
        UI.titled_section(title,  :verbose_prefix => '-> ') do
          target = sandbox.pod_dir(name)
          begin
            download_result = Downloader.download(download_request, target, :can_cache => can_cache)
          rescue Pod::DSLError => e
            raise Informative, "Failed to load '#{name}' podspec: #{e.message}"
          rescue => e
            raise Informative, "Failed to download '#{name}': #{e.message}"
          end

          spec = download_result.spec
          raise Informative, "Unable to find a specification for '#{name}'." unless spec
def download_request
        Downloader::Request.new(
          :name => name,
          :params => params,
        )
      end

? !

image.png

https://wenku.baidu.com/view/387eeb85f624ccbff121dd36a32d7375a417c6db.html

resuce

ruby 异常处理 begin rescue end

begin

     代码1

rescue

  代码2

end

如果执行 代码1 发生异常 则转至 代码2

若正常,则执行完跳出

运算符号

https://ke.qq.com/itdoc/ruby/ruby-operator.html

各种运算符

**
将右侧操作数指定为左侧操作数的指数

**=
指数幂并赋值运算符

<=>
组合比较运算符

.eql?
检查比较操作数相等和类型是否相同?

equal?
检查比较对象ID是否相等
//更多请阅读:https://www.yiibai.com/ruby/operators.html

<=>
组合比较运算符。如果第一个操作数等于秒,则返回0,如果第一个操作数大于第二个,则返回1,如果第一个操作数小于第二个则返回-1。

<=>
组合比较运算符。如果第一个操作数等于秒,则返回0,如果第一个操作数大于第二个,则返回1,如果第一个操作数小于第二个则返回-1。

10 等于?
如果接收方和参数具有相同的对象标识,则为真。

.join 和.tap 关键词

def self.capture_command!(executable, command, **kwargs)
      capture_command(executable, command, **kwargs).tap do |result|
        result = Array(result)
        status = result.last
        unless status.success?
          output = result[0..-2].join
          raise Informative, "#{executable} #{command.join(' ')}\n\n#{output}".strip
        end
      end
    end

join方法的定义

>> a
=> [42, 8, 17, 7, "foo", "bar"]
>> a.join                       # 没有连接符
=> "428177foobar"
>> a.join(', ')                 # 连接符是一个逗号和空格
=> "42, 8, 17, 7, foo, bar"

https://ruby-china.org/topics/5348
分享 Rails 技巧之 tap & try
当读者遇到:

user = User.new
user.username = "foobar"
user.save!

他们必须遵循所有三行,然后才能认识到它只是在创建一个名为user.

如果是:

user = User.new.tap do |u|
  u.username = "foobar"
  u.save!
end

那么这将立即清楚。读者不必阅读块内的内容即可知道实例user已创建。

正如博主所做的那样,使用点击只是一种方便的方法。在您的示例中,这可能有点矫枉过正,但在您想与用户一起做很多事情的情况下,点击可以说提供了一个更简洁的界面。因此,也许在以下示例中可能会更好:

user = User.new.tap do |u|
  u.build_profile
  u.process_credit_card
  u.ship_out_item
  u.send_email_confirmation
  u.blahblahyougetmypoint
end

使用上面的方法可以很容易地快速看到所有这些方法都组合在一起,因为它们都引用同一个对象(本例中的用户)。替代方案是:

user = User.new
user.build_profile
user.process_credit_card
user.ship_out_item
user.send_email_confirmation
user.blahblahyougetmypoint

同样,这是有争议的 - 但可以证明第二个版本看起来有点混乱,并且需要更多的人工解析才能看到所有方法都在同一个对象上被调用。

gsub

https://blog.csdn.net/sqlxx/article/details/8164554

ruby中带“!"和不带"!"的方法的最大的区别就是带”!"的会改变调用对象本身了。比方说str.gsub(/a/, 'b'),不会改变str本身,只会返回一个新的str。而str.gsub!(/a/, 'b')就会把str本身给改了。

但是gsub和gsub!还有另外一个不同点就是,gsub不管怎么样都会返回一个新的字符串,而gsub!只有在有字符被替换的情况下才会返回一个新的字符串,假如说没有任何字符被替换,gsub!只会返回nil.

example:

'abc'.gsub(/a/, 'b') #返回'bbc'

'abc'.gsub!(/a/, 'b') #返回'bbc'

'abc'.gsub(/d/,'a') #返回'abc'

'abc'.gsub!(/d/, 'a') #返回nil

scan match

https://blog.csdn.net/cz9025/article/details/90202839
用法:
新建文件xx.rb内容为:

module ModuleName
  def fn
    p "module cz"
  end
end

以获得module名为例:

Dir["xx.rb"].each do |file|
  name1 = File.read(file).scan(/module (.*)/)
  p name1
  name2 = File.read(file).match(/module (.*)/)
  p name2

  name3 = File.read(file).scan(/hh (.*)/)
  p name3
  name4 = File.read(file).match(/hh (.*)/)
  p name4
end

运行结果为:

区别

scan:

  查找全部匹配的内容,返回一个数组。

  如果未匹配到,返回[]。

  返回结果:()匹配到的内容。

match:

  只匹配第一次,返回为MatchData类型。

  如果未匹配到,返回nil。

  返回结果:完整匹配部分+()匹配到的内容。

.map(&:to_s)

https://wenku.baidu.com/view/39aae24e26c52cc58bd63186bceb19e8b8f6ecae.html

image.png

Hash.key?(obj)方法

https://www.nhooo.com/note/qa55qj.html

在本文中,我们将研究Hash.key?(obj)方法。由于该方法的名称完全不同,因此无法进行假设。让我们阅读其定义并在语法和程序代码的帮助下了解其实现。

方法说明:

该方法是Public实例方法,属于Hash类,它位于Ruby语言库中。Hash.key?()方法用于检查键(键值)是否为特定Hash实例的一部分,并且该Hash实例应为普通的Hash实例。它将搜索整个哈希,并根据其搜索结果。让我们来看一下语法,并演示该方法的程序代码。

如果您正在考虑它将返回什么,那么让我告诉您,它将返回一个布尔值。如果在哈希表中找到键,则返回值将为true;如果找不到哈希表实例的一部分,则返回值为false。

语法:

Hash_instance.key?(obj)

Argument(s) 需要:

此方法仅使用一个参数,而该参数不过是我们要检查其存在性的键。

范例1:

=begin
  Ruby program to demonstrate Hash.key? method
=end    

hsh = {"colors"  => "red","letters" => "a", "Fruit" => "Grapes"}

puts "Hash.key? implementation:"

puts "Enter the Key you want to search: "
ky = gets.chomp

if (hsh.key?(ky))
    puts "Key found successfully"
else
    puts "Key not found!"
end

输出

Hash.key? implementation:
Enter the Key you want to search: 
 colors
Key found successfully

在上面的代码中,您可以观察到我们在普通的Hash实例上调用Hash.key?()方法。当它在用户输入的哈希对象中发现键存在时,它返回true。

范例2:

=begin
  Ruby program to demonstrate Hash.key? method
=end    

hsh = {"colors"  => "red","letters" => "a", "Fruit" => "Grapes"}
hsh1 = {"cars"  => "800","bike" => "pulsar", "phone" => "A50"}
hsh2 = {"one"=> hsh, "two" => hsh1}

puts "Hash.key? implementation:"

puts "Enter the Key you want to search: "
ky = gets.chomp

if (hsh2.key?(ky))
    puts "Key found successfully"
else
    puts "Key not found!"
end

输出结果

Hash.key? implementation:
Enter the Key you want to search: 
 colors
Key not found!

说明:

在上面的代码中,您可以验证Hash.key?()方法不适用于作为多个Hash实例集合的Hash实例。即使对象是Hash实例的一部分,它也会返回false。

你可能感兴趣的:(cocoapods源码的ruby 语法学习)