Spec-Zone.ru › Ruby 3.3

класс OpenStruct

Родитель:
Объект

Структура данных OpenStruct, похожая на Hash, позволяет определять произвольные атрибуты со значениями. Это достигается с помощью метапрограммирования Ruby для определения методов в самом классе.

Примеры

require "ostruct"

person = OpenStruct.new
person.name = "John Smith"
person.age  = 70

person.name      # => "John Smith"
person.age       # => 70
person.address   # => nil

Объект OpenStruct использует Hash для внутреннего хранения атрибутов и значений и даже может быть инициализирован с помощью него:

australia = OpenStruct.new(:country => "Australia", :capital => "Canberra")
  # => #<OpenStruct country="Australia", capital="Canberra">

Ключи Hash с пробелами или символами, которые обычно не могут быть использованы для вызовов методов (например, ()[]*), не будут сразу доступны в объекте OpenStruct как методы для получения или присвоения, но к ним все равно можно получить доступ через метод Object#send или используя [].

measurements = OpenStruct.new("length (in inches)" => 24)
measurements[:"length (in inches)"]       # => 24
measurements.send("length (in inches)")   # => 24

message = OpenStruct.new(:queued? => true)
message.queued?                           # => true
message.send("queued?=", false)
message.queued?                           # => false

Для удаления атрибута необходимо выполнить метод delete_field, так как установка значения свойства в nil не удалит атрибут.

first_pet  = OpenStruct.new(:name => "Rowdy", :owner => "John Smith")
second_pet = OpenStruct.new(:name => "Rowdy")

first_pet.owner = nil
first_pet                 # => #<OpenStruct name="Rowdy", owner=nil>
first_pet == second_pet   # => false

first_pet.delete_field(:owner)
first_pet                 # => #<OpenStruct name="Rowdy">
first_pet == second_pet   # => true

Совместимость с Ractor: Замороженный объект OpenStruct с разделяемыми значениями сам по себе является разделяемым.

Ограничения

Объект OpenStruct использует структуру поиска методов Ruby для поиска и определения необходимых методов для свойств. Это достигается с помощью методов method_missing и define_singleton_method.

Это следует учитывать, если есть опасения по поводу производительности создаваемых объектов, так как при настройке этих свойств гораздо больше накладных расходов по сравнению с использованием Hash или Struct. Создание структуры open из небольшого Hash и доступ к нескольким записям может быть в 200 раз медленнее, чем прямой доступ к хэшу.

Это потенциальная проблема безопасности; создание OpenStruct из недоверенных данных пользователя (например, JSON веб-запрос) может быть уязвимо к атаке «отказ в обслуживании символа», поскольку ключи создают методы, а имена методов никогда не удаляются из памяти.

Это также может быть источником несовместимости между версиями Ruby:

o = OpenStruct.new
o.then # => nil in Ruby < 2.6, enumerator for Ruby >= 2.6

Встроенные методы могут быть переопределены таким образом, что это может быть источником ошибок или проблем безопасности:

o = OpenStruct.new
o.methods # => [:to_h, :marshal_load, :marshal_dump, :each_pair, ...
o.methods = [:foo, :bar]
o.methods # => [:foo, :bar]

Для решения конфликтов OpenStruct использует только защищенные/приватные методы, заканчивающиеся !, и определяет псевдонимы для встроенных публичных методов, добавляя !:

o = OpenStruct.new(make: 'Bentley', class: :luxury)
o.class # => :luxury
o.class! # => OpenStruct

Рекомендуется (но не обязательно) не использовать поля, заканчивающиеся !; Обратите внимание, что методы подкласса не могут быть переопределены, и собственные методы OpenStruct, заканчивающиеся !, тоже.

По всем этим причинам рекомендуется вообще не использовать OpenStruct.

Константы

HAS_PERFORMANCE_WARNINGS
VERSION

Методы публичного класса

json_create(object) Показать исходный код
# File ext/json/lib/json/add/ostruct.rb, line 10
def self.json_create(object)
  new(object['t'] || object[:t])
end

См. as_json.

new(hash=nil) Показать исходный код
# File lib/ostruct.rb, line 134
def initialize(hash=nil)
  if HAS_PERFORMANCE_WARNINGS && Warning[:performance]
     warn "OpenStruct use is discouraged for performance reasons", uplevel: 1, category: :performance
  end

  if hash
    update_to_values!(hash)
  else
    @table = {}
  end
end

Создаёт новый объект OpenStruct. По умолчанию, полученный объект OpenStruct не будет иметь атрибутов.

Необязательный hash, если задан, сгенерирует атрибуты и значения (может быть Hash, OpenStruct или Struct). Например:

require "ostruct"
hash = { "country" => "Australia", :capital => "Canberra" }
data = OpenStruct.new(hash)

data   # => #<OpenStruct country="Australia", capital="Canberra">

Методы публичного экземпляра

==(other) Показать исходный код
# File lib/ostruct.rb, line 423
def ==(other)
  return false unless other.kind_of?(OpenStruct)
  @table == other.table!
end

Сравнивает этот объект и other на равенство. Объект OpenStruct равен other, когда other является объектом OpenStruct, а таблицы Hash двух объектов равны.

require "ostruct"
first_pet  = OpenStruct.new("name" => "Rowdy")
second_pet = OpenStruct.new(:name  => "Rowdy")
third_pet  = OpenStruct.new("name" => "Rowdy", :age => nil)

first_pet == second_pet   # => true
first_pet == third_pet    # => false
ostruct[name] → object Показать исходный код
# File lib/ostruct.rb, line 303
def [](name)
  @table[name.to_sym]
end

Возвращает значение атрибута или nil, если такого атрибута нет.

require "ostruct"
person = OpenStruct.new("name" => "John Smith", "age" => 70)
person[:age]   # => 70, same as person.age
ostruct[name] = obj → obj Показать исходный код
# File lib/ostruct.rb, line 318
def []=(name, value)
  name = name.to_sym
  new_ostruct_member!(name)
  @table[name] = value
end

Устанавливает значение атрибута.

require "ostruct"
person = OpenStruct.new("name" => "John Smith", "age" => 70)
person[:age] = 42   # equivalent to person.age = 42
person.age          # => 42
Также алиас: set_ostruct_member_value!
as_json(*) Показать исходный код
# File ext/json/lib/json/add/ostruct.rb, line 30
def as_json(*)
  klass = self.class.name
  klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
  {
    JSON.create_id => klass,
    't'            => table,
  }
end

Методы OpenStruct#as_json и OpenStruct.json_create могут использоваться для сериализации и десериализации объекта OpenStruct; см. Marshal.

Метод OpenStruct#as_json сериализует self, возвращая хеш из 2 элементов, представляющий self:

require 'json/add/ostruct'
x = OpenStruct.new('name' => 'Rowdy', :age => nil).as_json
# => {"json_class"=>"OpenStruct", "t"=>{:name=>'Rowdy', :age=>nil}}

Метод JSON.create десериализует такой хеш, возвращая объект OpenStruct:

OpenStruct.json_create(x)
# => #<OpenStruct name='Rowdy', age=nil>
delete_field(name) { || ... } Показать исходный код
# File lib/ostruct.rb, line 371
def delete_field(name, &block)
  sym = name.to_sym
  begin
    singleton_class.remove_method(sym, "#{sym}=")
  rescue NameError
  end
  @table.delete(sym) do
    return yield if block
    raise! NameError.new("no field `#{sym}' in #{self}", sym)
  end
end

Удаляет поле с указанным именем из объекта и возвращает значение поля, если оно было определено. Вы можете необязательно предоставить блок. Если поле не определено, возвращается результат блока или возбуждается исключение NameError, если блок не был задан.

require "ostruct"

person = OpenStruct.new(name: "John", age: 70, pension: 300)

person.delete_field!("age")  # => 70
person                       # => #<OpenStruct name="John", pension=300>

Установка значения в nil не удалит атрибут:

person.pension = nil
person                 # => #<OpenStruct name="John", pension=nil>

person.delete_field('number')  # => NameError

person.delete_field('number') { 8675_309 } # => 8675309
dig(name, *identifiers) → object Показать исходный код
# File lib/ostruct.rb, line 340
def dig(name, *names)
  begin
    name = name.to_sym
  rescue NoMethodError
    raise! TypeError, "#{name} is not a symbol nor a string"
  end
  @table.dig(name, *names)
end

Ищет и возвращает объект в вложенных объектах, который задаётся name и identifiers. Вложенные объекты могут быть экземплярами различных классов. См. Методы dig.

Примеры:

require "ostruct"
address = OpenStruct.new("city" => "Anytown NC", "zip" => 12345)
person  = OpenStruct.new("name" => "John Smith", "address" => address)
person.dig(:address, "zip") # => 12345
person.dig(:business_address, "zip") # => nil
each_pair {|name, value| block } → ostruct Показать исходный код
each_pair → Enumerator
# File lib/ostruct.rb, line 211
def each_pair
  return to_enum(__method__) { @table.size } unless defined?(yield)
  @table.each_pair{|p| yield p}
  self
end

Возвращает все атрибуты (как символы) вместе с соответствующими значениями или возвращает перечислитель, если блок не задан.

require "ostruct"
data = OpenStruct.new("country" => "Australia", :capital => "Canberra")
data.each_pair.to_a   # => [[:country, "Australia"], [:capital, "Canberra"]]
eql?(other) Показать исходный код
# File lib/ostruct.rb, line 433
def eql?(other)
  return false unless other.kind_of?(OpenStruct)
  @table.eql?(other.table!)
end

Сравнивает этот объект и other на равенство. Объект OpenStruct равен other, когда other является объектом OpenStruct, а таблицы Hash двух объектов равны.

freeze() Показать исходный код
# File lib/ostruct.rb, line 269
def freeze
  @table.freeze
  super
end
Вызывает метод предка Object#freeze
inspect() Показать исходный код
# File lib/ostruct.rb, line 388
def inspect
  ids = (Thread.current[InspectKey] ||= [])
  if ids.include?(object_id)
    detail = ' ...'
  else
    ids << object_id
    begin
      detail = @table.map do |key, value|
        " #{key}=#{value.inspect}"
      end.join(',')
    ensure
      ids.pop
    end
  end
  ['#<', self.class!, detail, '>'].join
end

Возвращает строку, содержащую подробный обзор ключей и значений.

Также алиас: to_s
to_h(&block) Показать исходный код
# File lib/ostruct.rb, line 182
def to_h(&block)
  if block
    @table.to_h(&block)
  else
    @table.dup
  end
end
to_json(*args) Показать исходный код
# File ext/json/lib/json/add/ostruct.rb, line 48
def to_json(*args)
  as_json.to_json(*args)
end

Возвращает строку JSON, представляющую self:

require 'json/add/ostruct'
puts OpenStruct.new('name' => 'Rowdy', :age => nil).to_json

Вывод:

{"json_class":"OpenStruct","t":{'name':'Rowdy',"age":null}}
to_s()
Псевдоним для: inspect

Приватные методы экземпляра

set_ostruct_member_value!
Псевдоним для: []=

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API