Skip to content

Commit

Permalink
add default_attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
DannyBen committed Sep 10, 2020
1 parent f7e6096 commit 7fe6eac
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 17 deletions.
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ song.update! year: 1988, artist: 'Metallica' # this variant also saves

### Restricting / allowing certain attributes

You may specify required arguments. Records without these attributes will
not be saved. Note that `id` is always required
You may specify required attributes. Records without these attributes will
not be saved. Note that `id` is always required.

```ruby
class Song < ActiveCabinet
Expand Down Expand Up @@ -114,6 +114,22 @@ song.valid? # => false
song.error # => "invalid attributes: [:artist]"
```

### Declaring default attribute values

You may specify default values for some attributes. These attrributes will
be merged into newly created record instances.

```ruby
class Song < ActiveCabinet
required_attributes :title
default_attributes format: :mp3
end

song = Song.new title: "Moonchild"
song.format # => :mp3
```


### Configuring storage path

By default, `ActiveCabinet` stores all its files (two files per model) in the
Expand Down
23 changes: 22 additions & 1 deletion lib/active_cabinet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ActiveCabinet
#
# @param [Hash] attributes record attributes
def initialize(attributes = {})
@attributes = attributes.transform_keys(&:to_sym)
@attributes = default_attributes.merge attributes.transform_keys(&:to_sym)
end

# @!group Attribute Management
Expand Down Expand Up @@ -42,6 +42,10 @@ def optional_attributes
self.class.optional_attributes
end

def default_attributes
self.class.default_attributes
end

# Returns +true+ if the object is valid.
#
# @return [Boolean] +true+ if the record is valid.
Expand All @@ -63,6 +67,23 @@ def valid?
true
end

# @!group Attribute Accessors

# Returns the attribute value for the given key.
#
# @return [Object] the attribute value.
def [](key)
attributes[key]
end

# Sets the attribute value for the given key.
#
# @param [Symbol] key the attribute key.
# @param [Object] value the attribute value.
def []=(key, value)
attributes[key] = value
end

# @!group Dynamic Attribute Accessors

# Provides read/write access to {attributes}
Expand Down
54 changes: 48 additions & 6 deletions lib/active_cabinet/metaclass.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,46 @@ def all_attributes
end

# Returns an array of records for which the block returns true.
# When +query+ is provided, it should be a Hash with a single key and
# value. The result will be records that have a matching attribute.
#
# @example Search using a Hash query
# Song.where artist: "Iron Maiden"
#
# @example Search using a block
# Song.where { |record| record[:artist] == "Iron Maiden" }
#
# @yieldparam [Object] record all record instances.
def where
all.select { |record| yield record }
# @return [Array<Object>] record all record instances.
def where(query = nil)
if query
key, value = query.first
all.select { |record| record[key] == value }
else
all.select { |record| yield record }
end
end

# Returns the record matching the +id+.
# When providing a Hash with a single key-value pair, it will return the
# first matching object from the respective {where} query.
#
# @example Retrieve a record by ID
# Song.find 1
# Song[1]
#
# @example Retrieve a different attributes
# Song.find artist: "Iron Maiden"
# Song[artist: "Iron Maiden"]
#
# @return [Object, nil] the object if found, or +nil+.
def find(id)
attributes = cabinet[id]
attributes ? new(attributes) : nil
if id.is_a? Hash
where(id).first
else
attributes = cabinet[id]
attributes ? new(attributes) : nil
end
end
alias [] find

Expand All @@ -101,11 +129,13 @@ def drop

# @!group Attribute Management

# Returns an array containing {required_attributes} and {optional_attributes}.
# Returns an array containing the keys of all allowed attributes as
# defined by {required_attributes}, {optional_attributes} and
# {default_attributes}.
#
# @return [Array<Symbol>] array of required attribute keys.
def allowed_attributes
(optional_attributes || []) + required_attributes
(optional_attributes || []) + required_attributes + default_attributes.keys
end

# Sets the required record attribute names.
Expand Down Expand Up @@ -138,6 +168,18 @@ def optional_attributes(*args)
end
end

# Sets the default record attribute values.
#
# @param [Hash<Symbol, Object>] **attributes one or more attribute names and values.
# @return [Hash<Symbol, Object>] the hash of the default attributes.
def default_attributes(args = nil)
if args
@default_attributes = args
else
@default_attributes ||= {}
end
end

# @!group Utilities

# Returns all records as a hash, with record IDs as the keys.
Expand Down
49 changes: 42 additions & 7 deletions spec/active_cabinet/active_cabinet_metaclass_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

describe '::allowed_attributes' do
it "returns an array of required and optional attributes" do
expect(subject.allowed_attributes).to match_array([:id, :title, :artist, :album])
expect(subject.allowed_attributes).to match_array([:id, :title, :artist, :album, :format])
end
end

Expand Down Expand Up @@ -131,7 +131,14 @@

context "when the record is not found" do
it "returns nil" do
expect(subject.find(11)).to be_nil
expect(subject.find 11).to be_nil
end
end

context "when a hash is given" do
it "returns the first matching object via #where" do
result = subject.find title: "Master of Puppets"
expect(result).to be_a Song
end
end
end
Expand Down Expand Up @@ -179,7 +186,7 @@

context "with arguments" do
before { @original = subject.required_attributes }
after { subject.required_attributes @original}
after { subject.required_attributes @original }

it "sets the required attributes and always adds :id" do
subject.required_attributes :cake, :pizza
Expand All @@ -188,6 +195,24 @@
end
end

describe '::default_attributes', :focus do
context "without arguments" do
it "returns the default arguments hash" do
expect(subject.default_attributes).to eq(format: :mp3)
end
end

context "with arguments" do
before { @original = subject.default_attributes }
after { subject.default_attributes @original }

it "sets the default attributes" do
subject.default_attributes media: :cd
expect(subject.default_attributes).to eq({media: :cd})
end
end
end

describe '::size' do
it "returns the number of records" do
expect(subject.size).to eq 10
Expand All @@ -203,10 +228,20 @@
end

describe '::where' do
it "returns records matching the block" do
result = subject.where { |asset| asset.id > 7 }
expect(result.count).to eq 3
expect(result.map { |asset| asset.id }).to match_array [8, 9, 10]
context "when no query is provided" do
it "returns records matching the block" do
result = subject.where { |asset| asset.id > 7 }
expect(result.count).to eq 3
expect(result.map { |asset| asset.id }).to match_array [8, 9, 10]
end
end

context "when a query is provided" do
it "returns records matching the key => value pair" do
result = subject.where title: "Master of Puppets"
expect(result.count).to eq 10
expect(result.first).to be_a Song
end
end
end
end
15 changes: 14 additions & 1 deletion spec/active_cabinet/active_cabinet_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,22 @@
end
end

describe '#[]' do
it "returns the attribute value" do
expect(subject[:title]).to eq "Red Balloons"
end
end

describe '#[]=' do
it "sets the attribute value" do
subject[:title] = "Moonchild"
expect(subject.title).to eq "Moonchild"
end
end

describe '#allowed_attributes' do
it "returns an array of required and optional attributes" do
expect(subject.allowed_attributes).to match_array [:album, :artist, :id, :title]
expect(subject.allowed_attributes).to match_array [:album, :artist, :id, :title, :format]
end
end

Expand Down
1 change: 1 addition & 0 deletions spec/mocks/song.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Mocks
class Song < ActiveCabinet
required_attributes :title
default_attributes format: :mp3
optional_attributes :artist, :album

class << self
Expand Down

0 comments on commit 7fe6eac

Please sign in to comment.