Class: ActiveRow

Inherits:
Object
  • Object
show all
Defined in:
lib/active_row.rb

Constant Summary collapse

CONVERTERS =
:all

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.create(attr_hash) ⇒ Object

Accepts a hash. By convention, keys should be the names of attributes as defined in the CSV headers and the atrributes of the subclass. However, attributes names are not validated by this method.

Returns self if a row is successfully created.



60
61
62
63
64
65
66
# File 'lib/active_row.rb', line 60

def self.create(attr_hash)
  CSV.open(table_path, 'a+') do |csv| # a+ => append to document
    # concatenate an array of values [1, 'text', 'username']
    csv << CSV::Row.new(attr_hash.keys, attr_hash.values).fields
  end
  self.new(attr_hash)
end

.find(id = nil) ⇒ Object

Accepts a value for the id field.

Returns self if a row is found and returns nil if no row is found



25
26
27
28
29
# File 'lib/active_row.rb', line 25

def self.find(id = nil)
  csv_table = CSV.table(table_path, converters: CONVERTERS)
  csv_row = csv_table.find { |row| row.field(:id) == id }
  csv_row ? self.new(csv_row.to_hash) : nil
end

.find_by(attr_hash) ⇒ Object

Accepts a hash. By convention, keys should be the names of attributes as defined in the CSV headers and the atrributes of the subclass. However, attributes names are not validated by this method.

Returns self if a row is found and returns nil if no row is found.



36
37
38
39
40
41
42
# File 'lib/active_row.rb', line 36

def self.find_by(attr_hash)
  csv_table = CSV.table(table_path, converters: CONVERTERS)
  # Find the row where values in the CSV::Row are
  # equal to the values of the attributes that were provided
  csv_row = csv_table.find { |row| row.values_at(*attr_hash.keys) == attr_hash.values}
  csv_row ? self.new(csv_row.to_hash) : nil
end

.table_directoryObject



14
15
16
# File 'lib/active_row.rb', line 14

def self.table_directory
  "./tables/"
end

.table_nameObject



10
11
12
# File 'lib/active_row.rb', line 10

def self.table_name
  "#{self.name.downcase}s"
end

.table_pathObject



18
19
20
# File 'lib/active_row.rb', line 18

def self.table_path
  "#{self.table_directory}#{self.table_name}.csv"
end

Instance Method Details

#attributesObject

Returns a hash of the receiving’s instance variables.



126
127
128
129
130
131
132
133
# File 'lib/active_row.rb', line 126

def attributes
  attrs = {}
  instance_variables.each { |instance_variable|
    # Convert the instariable to a string, removing the @ (instance notation), and convert back to a symbol
    attrs[instance_variable.to_s[1..-1].to_sym] = instance_variable_get(instance_variable)
  }
  attrs
end

#attributes=(new_attributes) ⇒ Object



135
136
137
138
# File 'lib/active_row.rb', line 135

def attributes=(new_attributes)
  new_attributes.each { |key, value| instance_variable_set(key, value) }
  attributes
end

#destroyObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/active_row.rb', line 98

def destroy
  csv_table = CSV.table(table_path, converters: CONVERTERS)
  # Delete the row from the table if it is equivalent to the receiving instance.
  csv_table.delete_if do |row|
    row == CSV::Row.new(attributes.keys, attributes.values)
  end

  # Write the csv_table to a file, replacing the original
  File.open(table_path, 'w') do |f| # w => write-only
    f.write(csv_table.to_csv)
  end

  # Get the file's contents and close it
  file = File.open(table_path, 'rb')
  contents = file.read
  file.close

  # If all rows but the header have been deleted...
  if contents.lines.count < 2
     # then ensure the headers are still there.
     File.open(table_path, 'w') do |f| # w => write-only
      f.write(attributes.keys.map(&:to_s).join(','))
    end
  end
  self.freeze
end

#saveObject

Returns true if the row is successfully saved. (Otherwise, an error will have occurred).



45
46
47
48
49
50
51
52
53
# File 'lib/active_row.rb', line 45

def save
  attr_hash = self.attributes
  if self.class.find_by(attr_hash)
    return false
  else
    self.class.create(attr_hash)
    return true
  end
end

#update(attr_hash) ⇒ Object

Accepts a hash. By convention, keys should be the names of attributes as defined in the CSV headers and the atrributes of the subclass. However, attributes names are not validated by this method.

Returns new_row as an instance of the subclass, or returns false.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/active_row.rb', line 73

def update(attr_hash)
  # Prevent update of id field
  attr_hash.reject! { |k, v| k == :id || k == "id" }
  csv_table = CSV.table(table_path, converters: CONVERTERS)
  old_row = csv_table.find { |row| row.field(:id) == id }
  new_row = CSV::Row.new(old_row.headers, old_row.fields)

  # Assign new values to the row by param name (which should be a field name)
  attr_hash.each { |k, v| new_row[k] = v }
  # Delete the old_row
  csv_table = CSV.table(table_path, converters: CONVERTERS)
  csv_table.delete_if do |row|
    row == old_row
  end
  csv_table << new_row
  # Write the csv_table to a file, replacing the original
  File.open(table_path, 'w') do |f| # w => write-only
    f.write(csv_table.to_csv)
  end
  # Note: AR returns true if successful, false if not.
  # If AR is successful, it updates the receiving instance's attributes.
  # This returns a new instance with the variables on success.
  new_row ? self.class.new(new_row.to_hash) : false
end