MemoryRecord
Introduction
A simple library that handles a few records easily. With this library can flexibly managed immutable data.
Installation
Install as a standalone gem
$ gem install memory_record
Or install within application using Gemfile
$ bundle add memory_record
$ bundle install
Examples
Basic usage 1
class Palette
include MemoryRecord
memory_record [
{ key: :coral, },
{ key: :tomato, },
{ key: :gold, },
]
end
Palette[:tomato].key # => :tomato
Palette[:tomato].name # => "tomato"
Palette[:tomato].code # => 1
Basic usage 2
class Palette
include MemoryRecord
memory_record [
{ key: :coral, r: 255, g: 127, b: 0 },
{ key: :tomato, r: 255, g: 99, b: 71 },
{ key: :gold, r: 255, g: 215, b: 0 },
]
end
Palette[:tomato].key # => :tomato
Palette[:tomato].name # => "tomato"
Palette[:tomato].code # => 1
Palette[:tomato].r # => 255
Palette[:tomato].g # => 99
Palette[:tomato].b # => 71
Basic usage 3
class Palette
include MemoryRecord
memory_record [
{ key: :coral, r: 255, g: 127, b: 0 },
{ key: :tomato, r: 255, g: 99, b: 71 },
{ key: :gold, r: 255, g: 215, b: 0 },
]
def rgb
[r, g, b]
end
def hex
"#" + rgb.collect { |e| "%02X" % e }.join
end
def name
super.capitalize
end
end
Palette[:tomato].key # => :tomato
Palette[:tomato].name # => "Tomato"
Palette[:tomato].code # => 1
Palette[:tomato].rgb # => [255, 99, 71]
Palette[:tomato].hex # => "#FF6347"
Palette.collect(&:hex) # => ["#FF7F00", "#FF6347", "#FFD700"]
How to turn as an array?
Enumerable extended, so that each method is available
Palette.each { |e| ... }
Palette.collect { |e| ... }
How do I submit a form to select in Rails?
form.collection_select(:pallet_key, Palette, :key, :name) // object[pallet_key]=tomato
form.collection_select(:pallet_key, Palette, :code, :name) // object[pallet_key]=1
Either way can see it with Palette[pallet_key]
Is the reference in subscripts slow?
Since it has a hash internally using the key value as a key, it can be acquired with O (1).
Palette[1].name # => "Tomato"
Palette[:tomato].name # => "Tomato"
Instances always react to code and key
object = Palette[:tomato]
object.key # => :tomato
object.code # => 1
How do I add a method to an instance?
For that, I am creating a new class so I need to define it normally
name method is special?
If name is not defined, it defines a name method that returns key.to_s
to_s method is defined?
Alias of name, to_s is defined.
If there is no key, use fetch to get an error
Palette.fetch(:xxx) # => <KeyError: ...>
The following are all the same
Palette[:xxx] || :default # => :default
Palette.fetch(:xxx, :default} # => :default
Palette.fetch(:xxx) { :default } # => :default
Use fetch_if to ignore if the key is nil
Palette.fetch_if(nil) # => nil
Palette.fetch_if(:tomato) # => #<Palette:... @attributes={...}>
Palette.fetch_if(:xxx) # => <KeyError: ...>
Key validation
Palette.lookup_key(:tomato) # => :tomato
Palette.lookup_key("tomato") # => :tomato
Palette.lookup_key(1) # => :tomato
Palette.lookup_key(:xxx) # => nil
Palette.lookup_key(:xxx, :tomato) # => :tomato
Palette.lookup_key(:xxx) { :tomato } # => :tomato
Palette.lookup_key(:xxx, :tomato) # => :tomato
Palette.lookup_key(:xxx, :black) rescue $! # => #<KeyError: Palette.fetch(:black) does not match anything
A common example in Rails
palette_key = Palette.lookup_key(params[:palette_key], :tomato)
How to refer to other keys
class Foo
include MemoryRecord
memory_record [
{ key: :a, other_key: :x },
{ key: :b, other_key: :y },
{ key: :c, other_key: :z },
]
class << self
def lookup(v)
super || invert_table[v]
end
private
def invert_table
@invert_table ||= inject({}) {|a, e| a.merge(e.other_key => e) }
end
end
end
Foo[:a] == Foo[:x] # => true
Foo[:b] == Foo[:y] # => true
Foo[:c] == Foo[:z] # => true
How prohibit the hash key from being attr_reader automatically?
Use attr_reader: false
or attr_reader: {only: ...}
or attr_reader: {except: ...}
class Foo
include MemoryRecord
memory_record attr_reader: {only: :y} do
[
{ x: 1, y: 1, z: 1 },
]
end
end
Foo.first.x rescue $! # => #<NoMethodError: undefined method `x' for #<Foo:0x007fcc861ff108>>
Foo.first.y rescue $! # => 1
Foo.first.z rescue $! # => #<NoMethodError: undefined method `z' for #<Foo:0x007fcc861ff108>>
How to decide code yourself?
class Foo
include MemoryRecord
memory_record [
{ code: 1, key: :a, name: "A" },
{ code: 2, key: :b, name: "B" },
]
end
Foo.collect(&:code) # => [1, 2]
It is not recommended to specify it explicitly. It is useful only when refactoring legacy code with compatibility in mind.
Convert to JSON
Similar to ActiveModel's serialization, there is an only
except
methods
include
method.
class ColorInfo
include MemoryRecord
memory_record [
{ key: :blue, rgb: [ 0, 0, 255], },
{ key: :red, rgb: [255, 0, 0], },
]
def hex
"#" + rgb.collect { |e| "%02X" % e }.join
end
def children
[
{x: 1, y: 2},
{x: 3, y: 4},
]
end
end
color_info = ColorInfo.first
color_info.as_json # => {:key=>:blue, :rgb=>[0, 0, 255], :a=>1, :code=>0}
color_info.as_json(only: :key) # => {:key => :blue}
color_info.as_json(except: [:rgb, :code]) # => {:key => :blue}
color_info.as_json(only: [], methods: :hex) # => {:hex => "#0000FF"}
color_info.as_json(only: [], include: {children: {only: :x}} ) # => {:children => [{"x" => 1}, {"x" => 3}]}
ColorInfo.as_json(only: :key) # => [{:key=>:blue}, {:key=>:red}]
ColorInfo.to_json(only: :key) # => "[{\"key\":\"blue\"},{\"key\":\"red\"}]"
Case of ActiveModelSerializers
class ColorInfoSerializer < ActiveModel::Serializer
attributes :key
end
ActiveModelSerializers::SerializableResource.new(ColorInfo.first).as_json # => { :key => :blue }