かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Google スプレッドシート GAS replace が見つかりません。

SpreadSheet の GAS を書いていて .replace() でデータを整形しようとしたら TypeError:オブジェクト XXX で関数 replace が見つかりません。 というエラーが出てしまいました。

GASに replace メソッドが無いのかと思ったらそういう訳ではなく、値が数値だと自動変換されずにエラーになってしまうようです。

数値が入る可能性があるデータを replace する時は .toString() で文字列化する

例えば文字列で 60% や数値で 100 のような型が混在したデータを 0.6 のような形式に変換したい場合

example.gs

function dataFormat(data) {
  return data.map(function(value, index) {
    if(index === parTextCol) {
      // 数値が渡ってくるとエラーになるので一度 toString() で文字列化して % を除去する
      return (value.toString('%', '') - 0) / 100
    }
    // …
    return value
  });
}

const data = sheet.gatRange(startRow, startCol, rowNum, colNum)
  .map(function(row) {
    return dataFormat(row)
  });

 
よくよく考えたら JavaScript でも数値を .replace() しようとしたら同じエラーになるんだった…

const val = 12345;
val.replace('1', 'X');
// => TypeError: val.replace is not a function

val.toString().replace('1', 'X')
// => "X2345"

まとめ

数値に .replace() をするとエラーになるので、数値が渡ってくるのか文字列が渡ってくるのか分からない場合は .toString するのが安全

今日も一日ご安全に!


イワタニ カセットガス オレンジ 3本組 CB-250-OR

イワタニ カセットガス オレンジ 3本組 CB-250-OR

Ruby Classメソッドのアクセス権

権限の種類

  • public ... どこからでもアクセス可能。クラス内にメソッドを定義した際のデフォルトのアクセス権
  • protected ... そのクラスまたはサブクラスのインスタンスメソッドからしか呼び出すことができない
  • private ... レシーバーの省略形でしか呼び出すことができない ( self に対してしか呼び出すことができない)

権限の設定方法

  1. public, protected,private` のキーワードに続けてメソッド名を文字列またはシンボルで引き渡す
    ※ 先にメソッドが定義されている必要がある
  2. 引数なしの public, protected,private` キーワードを置くと、それ以降のメソッドはその権限になる
class MyClass
  # デフォルトでは public メソッド
  def public_method
    p 'public'
  end

  protected
  # これより下は protected になる
  def protected_method
    p 'protected'
  end

  private
  # これより下は private になる
  def private_method
    p 'private'
  end

  def call_protected_method
    protected_method
  end

  def call_private_method
    private_method
  end
  # public メソッドに指定
  public :call_protected_method, :call_private_method
end

c = MyClass.new
c.public_method # => "public"
# protected メソッドは外部から直接呼び出すことはできない
c.protected_method
# => NoMethodError protected method `protected_method' called
# private メソッドも外部から直接呼び出すことはできない
c.private_method
# => NoMethodError private method `private_method' called
c.call_protected_method # => "protected"
c.call_private_method   # => "private"

Protected と Private 権限の違い

protected はメソッドが定義されているクラスと、そのサブクラスのインスタンスメソッドから呼び出すことができる
privateself に対してのみ呼び出しが可能、つまり同じクラスのオブジェクトでも他のオブジェクトの持つ private メソッドは呼び出すことができない

Protected

class ClassPermission
  attr_reader :name
  def initialize(name)
    @name = name
  end

  def use_protected(recever = self)
    print "#{@name} call #{recever.name}.protected_method > "
    recever.protected_method
  end

  protected
  def protected_method
    p 'protected'
  end
end

# サブクラス
class SubClassPermission < ClassPermission
end

c1 = ClassPermission.new('C1')
c2 = ClassPermission.new('C2')
cSub = SubClassPermission.new('SubClass')

# 自身をレシーバーにじて protected メソッドを実行できる
c1.use_protected(c1)
# => C1 call C1.protected_method > "protected"

# 同じクラスインスタンスからレシーバーを通じて protected メソッドを実行できる
c2.use_protected(c1)
# => C2 call C2.protected_method > "protected"

# サブクラスのインスタンスからレシーバーを通じて protected メソッドを実行できる
cSub.use_protected(c1)
# => SubClass call C1.protected_method > "protected"

無関係なクラスインスタンスのメソッド内からはレシーバーを通じても呼び出すことはできない

class Hoo
  def use_protected(recever = self)
    puts "Hoo call #{recever.name}.protected_method"
    recever.protected_method
  rescue => e
    p e
  end
end

hoo = Hoo.new
hoo.use_protected(c1)
# => Hoo call C1.protected_method
# => NoMethodError: protected method `protected_method' called

Private

class ClassPermission
  attr_reader :name
  def initialize(name)
    @name = name
  end

  def call_private
    print "#{@name} call private_method > "
    private_method
  end

  def use_private(recever = self)
    puts "#{@name} call #{recever.name}.private_method > "
    recever.private_method
  end

  def call_recever_call_private(recever = self)
    puts "#{@name} call #{recever.name}.call_private >> "
    recever.call_private
  end

  private
  def private_method
    p 'private'
  end
end

c1 = ClassPermission.new('C1')
c2 = ClassPermission.new('C2')
class SubClassPermission < ClassPermission
end

c1.call_private
# => C1 call private_method > "private"

# private メソッドは self の省略形でしか呼び出すことができない
c1.use_private
# => C1 call C1.private_method >
# => NoMethodError: private method `private_method' called

# 当然他のクラスインタンスからレシーバーを通じて呼び出そうとしてもエラー
c2.use_private(c1)
# => C2 call C1.private_method >
# => NoMethodError: private method `private_method' called

# レシーバー自身の private メソッドを使っているメソッドを呼び出すのはOK
c1.call_recever_call_private(c1)
# => C1 call C1.call_private >
# => C1 call private_method > "private"

c2.call_recever_call_private(c1)
# => C2 call C1.call_private >>
# => C1 call private_method > "private"

# サブクラスからでもOK
cSub.call_recever_call_private(c1)
# => SubClass call C1.call_private >>
# => C1 call private_method > "private"

private メソッドを呼び出しているメソッドが public メソッドなら無関係なクラスからでも呼び出せる

class Hoo
  def call_recever_call_private(recever = self)
    puts "Hoo call #{recever.name}.call_private >> "
    recever.call_private
  end
end

hoo = Hoo.new
hoo.call_recever_call_private(c1)
# => Hoo call C1.call_private >>
# => C1 call private_method > "private"

private メソッドを呼び出しているメソッドが protected なら無関係のクラスのインスタンスメソッドからは呼び出せなくなる

class ClassPermission
  attr_reader :name
  def initialize(name)
    @name = name
  end

  protected
  def call_private
    print "#{@name} call private_method > "
    private_method
  end

  private
  def private_method
    p 'private'
  end
end

class Hoo
  def call_protected_recever_call_private(recever = self)
    puts "Hoo call #{recever.name}.call_private >> "
    recever.call_private
  rescue => e
    p e
  end
end

c1 = ClassPermission.new('c1')
hoo = Hoo.new
hoo.call_protected_recever_call_private(c1)
# => Hoo call c1.call_private >>
# => NoMethodError: protected method `call_private' called

まとめ

Ruby のクラスインスタンスメソッドの権限は public, protected, private があり、設定方法は2種類ある。
最もアクセス権が厳しいのが private で自身(self)からしか呼び出すことができない
protected は同じクラスのインスタンスだけでなく、子孫クラスのインスタンスメソッドからも呼び出すことができる


プログラミング言語 Ruby

プログラミング言語 Ruby

Ruby クラス変数・インスタンス変数 のメモ

Ruby お勉強の自分用メモ

インスタンス変数

インスタンスごとに異なる値を持つ変数
@ から始まる変数名で定義する
インスタンス変数はデフォルトでは外部からアクセスすることはできない、
アクセス可能にするにはアクセサの属性を設定する必要がある

class Todo
  def initialize(task, limit)
    # インスタンス変数
    @task = task
    @limit = limit
  end

  def display
    "#{@task}: limit: #{@limit}"
  end
end

todo01 = Todo.new('Taks01', '2019-11-10')
todo02 = Todo.new('Taks02', '2019-11-20')

puts todo01.display
# => "Taks01: limit: 2019-11-10"
puts todo02.display
# => "Taks01: limit: 2019-11-20"

# 外部から直接インスタンス変数にアクセスする際はできない
todo01.@task
# => syntax error

# アクセサが設定されていないのでインスタンス変数に触ることはできない
todo01.task
# => NoMethodError: undefined method `task`

# アクセサを設定
class Todo
  attr_accessor :task
end

# アクセサ (getter) が設定されたインスタン変数にはアクセス可能になる
p todo01.task # => "Taks01"

アクセサ属性

キーワードにインスタンス変数名をシンボルの形式で渡すことで設定

  • attr_accessor ... getter , setter を設定
  • attr_reader ... getter のみを設定
  • attr_writer ... setter のみを設定
class Idol
  attr_reader :name
  attr_writer :type
  attr_accessor :rank

  def initialize(name, type, rank = 100)
    @name = name
    @type = type
    @rank = rank
  end

  def display
    puts "#{@name} (#{@type}) Rank: #{@rank}"
  end
end

aoi = Idol.new('Kiriya Aoi', 'cool')
aoi.display
# => "Kiriya Aoi (cool) Rank: 100"

# attr_accessor は読み書き可能
p aoi.rank # => 100
aoi.rank = 3
p aoi.rank # => 3

# 設定されていない getter, setter を使おうとするとエラー
# attr_reader は getter のみ
p aoi.name
# => "Kiriya Aoi"
aoi.name = 'Hoshimiya Ichigo'
# => NoMethodError: undefined method `name='

# attr_writer は setter のみ
p aoi.type
# => NoMethodError: undefined method `type' for
aoi.type = 'pop'
aoi.display
# => Kiriya Aoi (pop) Rank: 3

attr_accessor の設定は下記の様に独自にgetter, setter を設定するのと同等

class Foo
  def initialize(name = 'foo')
    @name = name
  end
  # getter
  def name
    @name
  end
  # setter
  def name=(val)
    @name = val
  end
end

foo = Foo.new
p foo.name # => "foo"
foo.name = 'bar'
p foo.name # => "bar"

インスタンス変数は値がセットされて始めて生成される

class Idol
  attr_accessor :name

  def my_name_is(name)
    @name = name
  end
end

hoshimiya = Idol.new
# 値がセットされていない状態では存在しない扱い
p hoshimiya.instance_variables
# => []
p hoshimiya.name
# => nil

hoshimiya.my_name_is 'Ichigo'
p hoshimiya.instance_variables
# => [:@name]
p hoshimiya.name
# => "Ichigo"

アクセサの状態とインスタンス変数のアクセス可能な方法の違い

getter, setter の有無によってインスタンス変数にアクセス可能な表記とアクセスできない表記がある

class Hoo
  attr_accessor :read_get_var
  attr_reader :read_only_var
  attr_writer :write_only_var

  def initialize
    @read_get_var   = "has_accessor"
    @read_only_var  = "has_rader"
    @write_only_var = "has_writer"
    @no_accessor    = "no_accessor"
  end

  def call_by_at
    p @read_get_var   # => "has_accessor"
    p @read_only_var  # => "has_rader"
    p @write_only_var # => "has_writer"
    p @no_accessor    # => "no_accessor"
  end

  def call_by_self
    p self.read_get_var  # => "has_accessor"
    p self.read_only_var # => "has_rader"
    # getter メソッドの呼び出しになるのでエラーになる
    p self.write_only_var
    # => NoMethodError: undefined method `write_only_var`
    p self.no_accessor
    # => NoMethodError: undefined method `no_accessor`
  end

  def call_by_no_recever
    p read_get_var  # => "has_accessor"
    p read_only_var # => "has_rader"
    # getter メソッドの呼び出しになるのでエラーになる
    p write_only_var
    # => NameError: undefined local variable or method `write_only_var`
    p no_accessor
    # => NameError: undefined local variable or method `no_accessor`
  end
end

hoo = Hoo.new
# `@変数名` でアクセス
hoo.call_by_at

# `self.変数名` でアクセス
hoo.call_by_self

# `変数名` でアクセス
hoo.call_by_no_recever

メソッド内で @ 無しの変数名でのアクセスは、self の省略形になるので、self.変数名 と同じ結果になる

インスタンス変数はクラスからはアクセスできない

インスタンス変数は、アクセサを設定してもクラスからはアクセスできない

class Bar
  attr_accessor :my_name
  def initialize
    @my_name = 'bar'
  end
end

bar = Bar.new
p bar.my_name # => 'bar'
Bar.my_name
# => NoMethodError: undefined method `my_name' for Bar:Class

クラスメソッドのを作成してもインスタンス変数はインスタンスごとに異なる値を持つのでアクセスできない

class Bar
  attr_accessor :my_name
  def initialize
    @my_name = 'bar'
  end
  def self.my_name
    @my_name
  end
end
p Bar.my_name # => nil

クラス変数

@@ で始まる変数名で定義する
クラス変数は、クラスと子孫クラス・それらのクラスのインスタンス変数で共有される
クラス変数にはアクセサ属性が適応できないので、getter, setter は独自に設定する必要がある

class Foo
  @@class_name = 'foo'
  def display
    puts "#{self.class} class_name is #{@@class_name}"
  end
end

class Bar < Foo
  # instance getter
  def class_name
    @@class_name
  end
  # instance setter
  def class_name=(val)
    @@class_name = val
  end
end

class Baz < Foo
  # class getter
  def self.class_name
    @@class_name
  end
  # class setter
  def self.class_name=(val)
    @@class_name = val
  end
end

foo = Foo.new
bar = Bar.new
baz = Baz.new

foo.display # => Foo class_name is foo
bar.display # => Bar class_name is foo
baz.display # => Baz class_name is foo

bar.class_name = 'bar'
p bar.class_name # => "bar"
foo.display # => Foo class_name is bar
bar.display # => Bar class_name is bar
baz.display # => Baz class_name is bar

p Baz.class_name # => "bar"
Baz.class_name = "xxx"
p Baz.class_name # => "xxx"
p bar.class_name # => "xxx"
foo.display # => Foo class_name is xxx
bar.display # => Bar class_name is xxx
baz.display # => Baz class_name is xxx

# getter, setter を設定してないと外部からインスタンス変数同様アクセスできない
Foo.class_name
# => NoMethodError: undefined method `class_name`
foo.class_name
# => NoMethodError: undefined method `class_name`

クラス変数はインスタンスメソッド内でも定義できるが、メソッドを通って値が渡されるまでクラス変数は設定されない

class Hoo
  def initialize
    @@class_name = 'hoo!'
  end

  def self.class_name
    @@class_name
  end
end

p Hoo.class_name
  # => NameError: uninitialized class variable @@class_name in Hoo
p Hoo.class_variables # => []

hoo = Hoo.new
Hoo.class_name # => "hoo!"
Hoo.class_variables # => [:@@class_name]

継承させた子孫クラスでも同様

class Xoo < Hoo
  @@xoo_var = 'xoo'
  def self.xoo_var
    @@xoo_var
  end
end

# クラス変数に値が設定されていない状態だとエラー
Xoo.class_name
# => <NameError: uninitialized class variable @@class_name in Hoo

xoo = Xoo.new
# 親クラスのクラス変数に子孫クラスで値が設定されれば親クラスでも値が設定されている
p Hoo.class_name # => "hoo!"
p Hoo.class_variables # => [:@@class_name]
p Xoo.class_name # => "hoo!"

# 但し子孫クラスに設定されたクラス変数は親クラスでは参照できない
Xoo.xoo_var # => "xoo"
Hoo.xoo_var
# => NoMethodError: undefined method `xoo_var`

クラスインスタンス変数

クラスインスタンス変数は変数が設定されたクラスからのみ参照できる変数で、クラスのインスタンスや子孫クラスからは参照できない
変数名は @ から始めクラス定義はclass式内のトップレベルまたはクラスメソッド内に定義する (※ 通常のメソッド内で定義するとインスタンス変数になる)
クラスインスタンス変数は、クラス変数と同様でアクセサは自前で実装する必要がある

class CuteIdol
  # クラスインスタンス変数
  @type = 'cute'

  def initialize(name)
    # メソッド内で定義するとインスタンス変数になる
    @name = name
  end

  def say_my_type
    # クラスインスタンス変数はインスタンスからもアクセスできない
    p @type # => nil
  end

  def display
    # クラスからのみアクセスができるので `クラス名.クラスインスタンス変数名` でアクセスができるがgetterが無いと例外が発生する
    # self.type は getter があっても例外になるので注意!
    puts "#{@name} type is #{CuteIdol.type}!"
  end

  def self.display
    # クラスメソッドでは `@変数名` でアクセスが可能
    puts "#{self} Class type is #{@type}"
  end
end

CuteIdol.display
# => CuteIdol Class type is cute
p CuteIdol.instance_variables # => [:@type]

ichigo = CuteIdol.new('Hoshimiya Ichigo')
# クラスのインスタンスからもはアクセスできない
ichigo.say_my_type # => nil
# getter が無いと NoMethodError
ichigo.display
# => NoMethodError: undefined method `type`

class CuteIdol
  def self.type
    @type
  end

  def self.type=(val)
    @type = val
  end
end

ichigo.display
# => Hoshimiya Ichigo type is cute!

クラスメソッド内で定義

class Xoo
  def self.init
    @xoo = 'xoo'
  end

  def self.xoo
    @xoo
  end

  def xoo
    @xoo
  end
end

xoo = Xoo.new
Xoo.init
p Xoo.xoo # => xoo
p xoo.xoo # => nil

class Zoo < Xoo
end

p Zoo.xoo # => nils

クラスインスタンス変数は子孫クラスからもアクセスできない

class Foo
  @class_name = 'foo'

  def self.display
    puts "#{self} name is #{@class_name}"
  end

  def self.class_name
    @class_name
  end
end

class Hoo < Foo
  def self.hi
    p @class_name
  end
end

Foo.display # => "Foo name is foo"
p Foo.class_name # => "foo"
p Foo.instance_variables # => [:@class_name]

Hoo.display # => Hoo name is
Hoo.hi # => nil
p Hoo.class_name # => nil
p Hoo.instance_variables # => []

クラス定数

class式内のトップレベルに大文字から始まる変数を定義するとクラス定数になる
クラス定数は子孫クラスからもアクセス可能
定数なので変更しようとすると warning が発生する

class StarLightStudent
  SCHOOL_NAME = 'StarLight'

  attr_reader :name
  def initialize(name)
    @name = name
  end

  def display
    puts "#{@name} - #{SCHOOL_NAME} Scholl"
  end
end

class Idol < StarLightStudent
  def initialize(name, type)
    super name
    @type = type
  end

  def display
    puts "#{@name} (#{@type}) - #{SCHOOL_NAME} Scholl"
  end
end

p StarLightStudent::SCHOOL_NAME
# => "StarLight"

akari = StarLightStudent.new('Ozora Akari')
akari.display
# => "Ozora Akari - StarLight Scholl"

ichigo = Idol.new('Hoshimiya Ichigo', 'cute')
ichigo.display
# => "Hoshimiya Ichigo (cute) - StarLight Scholl"

クラス定数に外部からアクセスするには getter を独自に作成する必要がある
setter を定義すると warning が発生する

class Week
  DAY_OF_WEEK = 7

  def self.DAY_OF_WEEK
    DAY_OF_WEEK
  end

  def self.DAY_OF_WEEK=(val)
    DAY_OF_WEEK = val
    # => dynamic constant assignment
  end
end

p Week.DAY_OF_WEEK # => 7

# warning が発生するが値の更新は可能
Week::DAY_OF_WEEK = 3
# warning: already initialized constant Week::DAY_OF_WEEK

p Week.DAY_OF_WEEK # => 3

トップレベルに定義された定数は Object のクラス定数として定義される

HOGE = 'hoge!'
p Object::HOGE # => "hoge!"

class Hoge
  HOGE = 'fugafuga'
  def say
    p HOGE # => "fugafuga"
    # トップレベルの定数を参照する
    p Object::HOGE # => "hogehoge!"
  end
end

Hoge.new.say

クラスの定義は、クラスを表す Class クラスのインスタンスを作成し、そのインスタンスを参照するクラス名の定数を作成するので、クラス名と定数名が被っているとエラーになる

HOGE = 'hoge!'

class HOGE
end
# => HOGE is not a class (TypeError)

まとめ

  • インスタンス変数はクラス内のメソッドで使う時は @変数名 にしておけば間違いなさそう
  • クラス内に作れる変数は、外部からアクセスするには基本的にアクセサが必要
    インスタンス変数は attr_ でアクセサを作成することができるが、それ以外は独自に必要なメソッドを作成する必要がある
  • インスタンス変数は @ で始まる変数名でメソッド内に定義
    変数定義は子孫クラスにも引き継がれインスタンスごとに異なる値を持つのでインスタンスからのみアクセス可能
    インスタンス変数は、値がセットされて始めて生成される
  • クラス変数は @@ で始まる変数名で定義・クラス定数は 大文字から始まる変数名で定義
    クラス変数・クラス定数は、クラスと子孫クラス、それらのインスタンスから参照できる
  • クラスインスタンス変数は @ で始まる変数名で class式内のトップレベルまたは、クラスメソッド内に定義 クラスインスタンス変数は、変数の定義されたクラスからのみ参照可能
  • クラス定義はトップレベルに定数として定義される

初めてのRuby

初めてのRuby