class RichText::Op

Operations are the immutable units of rich-text deltas and documents. As such, we have a class that wraps these values and provides convenient methods for querying type and contents, and for subdividing as needed by {Delta#slice}.

Constants

TYPES

Attributes

attributes[R]

@return [Hash]

type[R]

@return [Symbol] one of {TYPES}

value[R]

@return [String, Integer, Hash] value depends on type

Public Class Methods

new(type, value, attributes = nil) click to toggle source

Creates a new Op object, based on a type, value, and attributes. No sanity checking is performed on the arguments; please use {Op.parse} for dealing with untrusted user input. @param type [Symbol] one of {TYPES} @param value [Integer, String, Hash] various values corresponding to type @param attributes [Hash] @return [Op]

# File lib/rich-text/op.rb, line 51
def initialize(type, value, attributes = nil)
  @type = type.to_sym
  @value = value.freeze
  @attributes = (attributes || {}).freeze
end
parse(data) click to toggle source

Creates a new Op object from a Hash. Used by {Delta#initialize} to parse raw data into a convenient form. @param data [Hash] containing exactly one of {TYPES} as a key, and optionally an `:attributes` key. munged to provide indifferent access via String or Symbol keys @return [Op] @raise [ArgumentError] if `data` contains invalid keys, i.e. zero or more than one of {TYPES} @example

RichText::Op.parse({ insert: 'abc', attributes: { bold: true } })
# => #<RichText::Op insert="abc" {"bold"=>true}>

RichText::Op.parse({ insert: 'abc', retain: 3 })
# => ArgumentError: must be a Hash containing exactly one of the following keys: [:insert, :retain, :delete]
# File lib/rich-text/op.rb, line 25
def self.parse(data)
  data = data.to_h.with_indifferent_access
  type_keys = (data.keys & TYPES.map(&:to_s))
  if type_keys.length != 1
    raise ArgumentError.new("must be a Hash containing exactly one of the following keys: #{TYPES.inspect}")
  end

  type = type_keys.first.to_sym
  value = data[type]
  if [:retain, :delete].include?(type) && !value.is_a?(Integer)
    raise ArgumentError.new("value must be an Integer when type is #{type.inspect}")
  end

  attributes = data[:attributes]
  if attributes && !attributes.is_a?(Hash)
    raise ArgumentError.new("attributes must be a Hash")
  end

  self.new(type, value, attributes)
end

Public Instance Methods

==(other) click to toggle source

An Op is equal to another if type, value, and attributes all match @param other [Op] @return [Boolean]

# File lib/rich-text/op.rb, line 148
def ==(other)
  other.is_a?(Op) && type == other.type && value == other.value && attributes == other.attributes
end
Also aliased as: eql?
attributes?() click to toggle source

@return [Boolean] whether any attributes are present; `false` when attributes is empty, `true` otherwise. @example

RichText::Op.new(:insert, 'abc').attributes? # => false
RichText::Op.new(:insert, 'abc', {}).attributes? # => false
RichText::Op.new(:insert, 'abc', { bold: true }).attributes? # => true
# File lib/rich-text/op.rb, line 62
def attributes?
  !attributes.empty?
end
delete?() click to toggle source

Returns whether type is `:delete` or not @returns [Boolean]

# File lib/rich-text/op.rb, line 85
def delete?
  type == :delete
end
eql?(other)
Alias for: ==
insert?(kind = Object) click to toggle source

Returns whether type is `:insert`, and value is an instance of `kind` @param kind [Class] pass a class to perform an additional `is_a?` check on {value} @return [Boolean] @example

RichText::Op.new(:insert, 'abc').insert? # => true
RichText::Op.new(:insert, 'abc').insert?(String) # => true
RichText::Op.new(:insert, { image: 'http://i.imgur.com/y6Eo48A.gif' }).insert?(String) # => false
# File lib/rich-text/op.rb, line 73
def insert?(kind = Object)
  type == :insert && value.is_a?(kind)
end
inspect(wrap = true) click to toggle source

A string useful for debugging, that includes type, value, and attributes. @param wrap [Boolean] pass false to avoid including the class name (used by {Delta#inspect}) @return [String] @example

RichText::Op.new(:insert, 'abc', { bold: true }).inspect # => '#<RichText::Op insert="abc" {:bold=>true}>'
RichText::Op.new(:insert, 'abc', { bold: true }).inspect(false) => 'insert="abc" {:bold=>true}'
# File lib/rich-text/op.rb, line 139
def inspect(wrap = true)
  str = "#{type}=#{value.inspect}"
  str << " #{attributes.inspect}" if attributes?
  wrap ? "#<#{self.class.name} #{str}>" : str
end
length() click to toggle source

Returns a number indicating the length of this op, depending of the type:

  • for `:insert`, returns `value.length` if a String, 1 otherwise

  • for `:retain` and `:delete`, returns value

@return [Integer]

# File lib/rich-text/op.rb, line 94
def length
  case type
  when :insert
    value.is_a?(String) ? value.length : 1
  when :retain, :delete
    value
  end
end
retain?() click to toggle source

Returns whether type is `:retain` or not @return [Boolean]

# File lib/rich-text/op.rb, line 79
def retain?
  type == :retain
end
slice(start = 0, len = length) click to toggle source

Returns a copy of the op with a subset of the value, measured in number of characters. An op may be subdivided if needed to return at most the requested length. Non-string inserts cannot be subdivided (naturally, as they have length 1). @param start [Integer] starting offset @param len [Integer] how many characters @return [Op] whose length is at most `len`

# File lib/rich-text/op.rb, line 108
def slice(start = 0, len = length)
  if insert?(String)
    Op.new(:insert, value.slice(start, len), attributes)
  elsif insert?
    unless start == 0 && len == 1
      raise ArgumentError.new("cannot subdivide a non-string insert")
    end
    dup
  else
    Op.new(type, [value - start, len].min, attributes)
  end
end
to_h() click to toggle source

@return [Hash] the Hash representation of this object, the inverse of {Op.parse}

# File lib/rich-text/op.rb, line 122
def to_h
  { type => value }.tap do |json|
    json[:attributes] = attributes if attributes?
  end
end
to_json(*args) click to toggle source

@return [String] the JSON representation of this object, by delegating to {#to_h}

# File lib/rich-text/op.rb, line 129
def to_json(*args)
  to_h.to_json(*args)
end