fixed_record 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +70 -14
- data/lib/fixed_record.rb +74 -21
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0eea6e2937878d931df67a139cff38882002163f62f43e9f6b4e9440c84bbc60
|
4
|
+
data.tar.gz: 8d51b0834f97783271b77fd8762289efad419c463aa3a6f705affded0a07de2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39687e91690bd8426119d2c41b77298dc3a48c2da4000a57bc6160f14ea2eb021d4495eac2ca27d50189fa5fcedbb2196c4c543bda44ff936aba2cf27d4f9b42
|
7
|
+
data.tar.gz: '0697f532ce75a0e808fefe5a94a9fa42b9fa00e346c7e6dda1288066aab857ab36d196a57473134d04d66ad4aa0b4b91a4db57a8197284a5c49ff9cfaf18b432'
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -4,13 +4,11 @@ FixedRecord provides ActiveRecord-like read-only access to a set of records
|
|
4
4
|
described in a YAML file.
|
5
5
|
|
6
6
|
Why is this useful? Occasionally you have tabular data which hardly ever
|
7
|
-
changes and can easily be edited by hand. Although this
|
8
|
-
|
9
|
-
It's quicker and simpler to implement this as an array of objects in a YAML file.
|
10
|
-
|
11
|
-
See the Usage section below
|
7
|
+
changes and can easily be edited by hand. Although this data could be placed in a database, it may not be worth the overhead involved (loading a database, maintaining database code, etc.).
|
12
8
|
|
9
|
+
It may be quicker and simpler to implement this as an array or hash of objects in a YAML file, and use this gem to provide access to the data.
|
13
10
|
|
11
|
+
See the Usage section below.
|
14
12
|
|
15
13
|
## Installation
|
16
14
|
|
@@ -30,6 +28,8 @@ Or install it yourself as:
|
|
30
28
|
|
31
29
|
## Usage
|
32
30
|
|
31
|
+
### Array of Records
|
32
|
+
|
33
33
|
Create a YAML file defining an array of records like this:
|
34
34
|
|
35
35
|
```yaml
|
@@ -45,7 +45,7 @@ Create a YAML file defining an array of records like this:
|
|
45
45
|
Then to load these, create a class
|
46
46
|
|
47
47
|
```ruby
|
48
|
-
require '
|
48
|
+
require 'fixed_record'
|
49
49
|
|
50
50
|
class MyFavoriteWebsite < FixedRecord
|
51
51
|
data "#{Rails.root}/data/my_favorite_websites.yml"
|
@@ -68,19 +68,78 @@ end
|
|
68
68
|
Or can be accessed as an array:
|
69
69
|
|
70
70
|
```ruby
|
71
|
-
|
71
|
+
MyFavoriteWebsite.all.is_a?(Array) # true
|
72
|
+
```
|
73
|
+
A count of the number of records is available:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
puts MyFavoriteWebsite.count
|
77
|
+
```
|
78
|
+
|
79
|
+
The declared class will also include all the methods from the `Enumerable` module.
|
80
|
+
|
81
|
+
### Hash of Records
|
82
|
+
|
83
|
+
Create a YAML file `my_web_pages.yml` defining a hash of records like this:
|
84
|
+
|
85
|
+
```yaml
|
86
|
+
StaticPage#first:
|
87
|
+
title: First Page
|
88
|
+
description: Welcome to the First Page
|
89
|
+
|
90
|
+
StaticPage#last:
|
91
|
+
title: Last Page
|
92
|
+
description: Welcome to the Last Page
|
93
|
+
|
94
|
+
```
|
95
|
+
|
96
|
+
Then to load these, create a class
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
require 'fixed_record'
|
100
|
+
|
101
|
+
class MyWebPages < FixedRecord
|
102
|
+
data "#{Rails.root}/data/my_web_pages.yml"
|
103
|
+
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
The collection can be accessed by index:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
MyWebPages['StaticPage#first'].title # First Page
|
111
|
+
MyWebPages['StaticPage#last'].description # Welcome to he Last page
|
112
|
+
MyWebPages['StaticPage#first'].key # StaticPage#fifst
|
113
|
+
```
|
114
|
+
|
115
|
+
The collection can then be enumerated as required:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
MyWebPages.each do |k,v|
|
119
|
+
puts k
|
120
|
+
puts v.title
|
121
|
+
end
|
122
|
+
```
|
123
|
+
Or can be accessed as an hash:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
MyWebPages.all.is_a?(Hash) # true
|
72
127
|
```
|
73
128
|
A count of the number of records is available:
|
74
129
|
|
75
130
|
```ruby
|
76
|
-
puts
|
131
|
+
puts MyWebPages.count
|
77
132
|
```
|
78
133
|
|
79
|
-
The class also
|
134
|
+
The declared class will also include all the methods from the `Enumerable` module.
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
## Error Checking
|
80
139
|
|
81
140
|
Some basic sanity checks are performed on the YAML file to catch common errors:
|
82
141
|
|
83
|
-
* It must define a non-empty array of records
|
142
|
+
* It must define a non-empty array or hash of records
|
84
143
|
* All records must have the same set of attributes
|
85
144
|
|
86
145
|
An `ArgumentError` exception will be thrown if any errors are detected.
|
@@ -89,9 +148,6 @@ Additional validations can be performed by overriding the `validate_yaml` and
|
|
89
148
|
`validate_item` class functions.
|
90
149
|
|
91
150
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
151
|
## Development
|
96
152
|
|
97
153
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -100,4 +156,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
100
156
|
|
101
157
|
## Contributing
|
102
158
|
|
103
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
159
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/m-z-b/fixed_record.
|
data/lib/fixed_record.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'yaml'
|
3
3
|
|
4
4
|
class FixedRecord
|
5
|
-
VERSION = "0.
|
5
|
+
VERSION = "0.2.0"
|
6
6
|
|
7
7
|
# Lazy load data from given filename
|
8
8
|
# creating accessors for top level attributes
|
@@ -28,43 +28,96 @@ class FixedRecord
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.count
|
31
|
-
all.
|
31
|
+
all.length
|
32
32
|
end
|
33
33
|
|
34
|
+
def self.[]( k )
|
35
|
+
if all.is_a?(Hash)
|
36
|
+
all[k]
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.has_key?( k )
|
43
|
+
if all.is_a?(Hash)
|
44
|
+
all.has_key?( k )
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
34
50
|
def self.load!
|
35
51
|
if @@items.nil?
|
36
52
|
y = YAML.load_file( filename )
|
37
53
|
validate_yaml( y )
|
38
|
-
valid_keys =
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
54
|
+
valid_keys = nil
|
55
|
+
if y.is_a?(Array)
|
56
|
+
valid_keys = y.first.keys
|
57
|
+
@@items = y.map.with_index do |values,i|
|
58
|
+
validate_item( valid_keys, values, i )
|
59
|
+
r = new
|
60
|
+
r.instance_variable_set( :@values, values )
|
61
|
+
r
|
62
|
+
end
|
63
|
+
elsif y.is_a?(Hash)
|
64
|
+
@@items = Hash.new
|
65
|
+
add_key = true
|
66
|
+
y.each do |k,values|
|
67
|
+
if valid_keys.nil?
|
68
|
+
valid_keys = values.keys
|
69
|
+
add_key = !values.has_key?('key')
|
70
|
+
end
|
71
|
+
validate_item( valid_keys, values, k )
|
72
|
+
values['key'] = k if add_key
|
73
|
+
r = new
|
74
|
+
r.instance_variable_set( :@values, values )
|
75
|
+
@@items[k] = r
|
76
|
+
end
|
77
|
+
valid_keys << 'key' if add_key
|
48
78
|
end
|
79
|
+
create_methods( valid_keys )
|
49
80
|
end
|
50
81
|
end
|
51
82
|
}
|
52
83
|
end
|
53
84
|
|
85
|
+
# Create access methods for each of valid_keys
|
86
|
+
def self.create_methods( valid_keys )
|
87
|
+
valid_keys.each do |k|
|
88
|
+
define_method( k.to_sym) { @values[k] }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
54
92
|
# Validate the top level of the data structure returned
|
55
93
|
def self.validate_yaml( y )
|
56
|
-
|
57
|
-
|
94
|
+
if y.is_a?(Array)
|
95
|
+
if y.length <= 0
|
96
|
+
throw ArgumentError.new "#{filename} contain a zero length array"
|
97
|
+
end
|
98
|
+
if y.any?{ |i| !i.is_a?(Hash)}
|
99
|
+
throw ArgumentError.new "#{filename} does not contain an array of items (hashes)"
|
100
|
+
end
|
101
|
+
elsif y.is_a?(Hash)
|
102
|
+
if y.count <= 0
|
103
|
+
throw ArgumentError.new "#{filename} contain an empty hash"
|
104
|
+
end
|
105
|
+
if y.any?{ |k,v| !v.is_a?(Hash) }
|
106
|
+
throw ArgumentError.new "#{filename} does not contain an array of items (hashes)"
|
107
|
+
end
|
108
|
+
else
|
109
|
+
throw ArgumentError.new "#{filename} does not contain a hash of items or an array of items"
|
58
110
|
end
|
111
|
+
|
59
112
|
end
|
60
113
|
|
61
|
-
# Validate a
|
62
|
-
def self.validate_item(
|
63
|
-
raise ArgumentError, "#{filename} item #{index
|
64
|
-
raise ArgumentError, "#{filename} item #{index
|
65
|
-
|
66
|
-
unless
|
67
|
-
raise ArgumentError, "#{filename} item #{index
|
114
|
+
# Validate a values of name -> value
|
115
|
+
def self.validate_item( valid_keys, values, index )
|
116
|
+
raise ArgumentError, "#{filename} item #{index} should be name value pairs" unless values.is_a?(Hash)
|
117
|
+
raise ArgumentError, "#{filename} item #{index} has wrong number of values" if valid_keys.length != values.length
|
118
|
+
valid_keys.each do |name|
|
119
|
+
unless values.has_key? name
|
120
|
+
raise ArgumentError, "#{filename} item #{index} is missing value for '#{name}'"
|
68
121
|
end
|
69
122
|
end
|
70
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fixed_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bell
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
|
-
rubygems_version: 3.
|
94
|
+
rubygems_version: 3.1.2
|
95
95
|
signing_key:
|
96
96
|
specification_version: 4
|
97
97
|
summary: Provide ActiveRecord like read-only access to a small dataset stored in a
|