Class: SDStruct

Inherits:
Object
  • Object
show all
Defined in:
lib/sd_struct.rb,
lib/sd_struct/version.rb

Overview

Alternative to OpenStruct that is more strict and go deeper.

Author:

  • Adrian Setyadi

Constant Summary collapse

InspectKey =

:nodoc:

:__inspect_key__
VERSION =
"0.0.3"

Instance Method Summary collapse

Constructor Details

#initialize(hash = nil, deep = true) ⇒ SDStruct

Returns a new instance of SDStruct.



54
55
56
57
58
59
60
61
62
# File 'lib/sd_struct.rb', line 54

def initialize(hash = nil, deep = true)
  @table = {}
  if hash
    hash.each_pair do |k, v|
      v = v.to_struct if deep && ( v.is_a?(Hash) || v.is_a?(Array) )
      @table[new_member(k)] = v
    end
  end
end

Instance Method Details

#==(other) ⇒ Object



199
200
201
202
# File 'lib/sd_struct.rb', line 199

def ==(other)
  return false unless other.kind_of?(self.class)
  @table == other.table
end

#[](name) ⇒ Object



114
115
116
# File 'lib/sd_struct.rb', line 114

def [](name)
  @table.has_key?(name) ? @table[name] : @table[name.to_s.underscore.to_sym]
end

#[]=(name, value) ⇒ Object



118
119
120
# File 'lib/sd_struct.rb', line 118

def []=(name, value)
  @table[new_member(name)] = value
end

#delete_field(name) ⇒ Object Also known as: delete_key



226
227
228
229
230
231
232
# File 'lib/sd_struct.rb', line 226

def delete_field(name)
  sym = name.to_sym
  @table.delete(sym) do
    raise NameError.new("no field `#{sym}' in #{self}", sym)
  end
  singleton_class.__send__(:remove_method, sym, "#{sym}=")
end

#dig(*args) ⇒ Object



169
170
171
# File 'lib/sd_struct.rb', line 169

def dig(*args)
  @table.dig(*args)
end

#dig_deep(*args) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/sd_struct.rb', line 147

def dig_deep(*args)
  full_args = args.dup
  parent_key = args.shift
  result = dig(parent_key)
  unless result.nil? || args.length.zero?
    if result.respond_to?(:dig)
      result = result.dig(*args)
    end
  end
  if result.nil?
    @table.values
          .select{|v| v.respond_to?(:dig) }
          .each do |v|
            if v.respond_to?(:dig_deep) || v.is_a?(Array)
              result = v.dig_deep(*full_args)
            end
            return result unless result.nil?
          end
  end
  return result
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


204
205
206
207
# File 'lib/sd_struct.rb', line 204

def eql?(other)
  return false unless other.kind_of?(self.class)
  @table.eql?(other.table)
end

#find(key_str, opt = {}) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/sd_struct.rb', line 173

def find(key_str, opt = {})
  opt = {
    separator: "/"
  }.merge(opt)

  args = key_str.split(opt[:separator])
                .map do |x|
                  x.strip!
                  if !!(x =~ /\A[-+]?\d+\z/)
                    x.to_i
                  else
                    if x[/\s+/]
                      x
                    else
                      x.underscore.to_sym
                    end
                  end
                end

  result = dig_deep(*args) rescue nil
  return result
end

#hashObject



209
210
211
# File 'lib/sd_struct.rb', line 209

def hash
  @table.hash
end

#initialize_copy(orig) ⇒ Object



64
65
66
67
# File 'lib/sd_struct.rb', line 64

def initialize_copy(orig)
  super
  @table = @table.dup
end

#inspectObject Also known as: to_s



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/sd_struct.rb', line 124

def inspect
  str = "#<#{self.class}"

  ids = (Thread.current[InspectKey] ||= [])
  if ids.include?(object_id)
    return str << ' ...>'
  end

  ids << object_id
  begin
    first = true
    for k,v in @table
      str << "," unless first
      first = false
      str << " #{k[/\s+/] ? "['#{k}']" : ".#{k}"}=#{v.inspect}"
    end
    return str << '>'
  ensure
    ids.pop
  end
end

#keysObject



222
223
224
# File 'lib/sd_struct.rb', line 222

def keys
  @table.keys
end

#marshal_dumpObject



69
70
71
# File 'lib/sd_struct.rb', line 69

def marshal_dump
  to_h
end

#marshal_load(x) ⇒ Object



73
74
75
76
# File 'lib/sd_struct.rb', line 73

def marshal_load(x)
  @table = x.map{|a| ( a.is_a?(Hash) || a.is_a?(Array) ) ? a.to_struct : a }
            .original_to_h
end

#non_spaced_keysObject Also known as: fields



217
218
219
# File 'lib/sd_struct.rb', line 217

def non_spaced_keys
  methods(false).select{|x| x[/^\S+[^=]$/]}
end

#spaced_keysObject



213
214
215
# File 'lib/sd_struct.rb', line 213

def spaced_keys
  @table.keys - non_spaced_keys
end

#to_h(opt = {}) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/sd_struct.rb', line 78

def to_h(opt = {})
  opt = {
    camelize_keys: false,
    exclude_blank_values: false,
    values_to_exclude: []
  }.merge(opt)

  @table.map do |k, v|
    v = v.to_h(opt) if v.is_a?(self.class) || v.is_a?(Array)
    k = k.to_s.camelize(:lower) if opt[:camelize_keys] && !k[/\s+/]
    [k, v]
  end.original_to_h
     .select{|_,v| opt[:exclude_blank_values] ? v.present? : !v.nil? }
     .select{|_,v| !v.in?(opt[:values_to_exclude]) }
end

#to_json(opt = {}) ⇒ Object



94
95
96
97
98
99
100
101
102
# File 'lib/sd_struct.rb', line 94

def to_json(opt = {})
  opt = {
    camelize_keys: true,
    exclude_blank_values: true,
    values_to_exclude: [0, [""], [{}]]
  }.merge(opt)

  to_h(opt).to_json
end