fixed_record 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +31 -7
- data/lib/fixed_record.rb +51 -25
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 156863124ec2fb0ca1668bafa2b16de94d622f577ea554ace2189dd24758bfa4
|
4
|
+
data.tar.gz: caf2f4fb5e63bd96218dc25eeeda8ede9bf792acc35bebb992aecb2068a395de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c40bf0b31215154be4a30ee76c4db815a88b24d3f1fa6e8f3be0ddd27225db9e22c0a446a6c624adb313bf6e83ef45e12f2f4b2c2a9e7801811fa2966ef3108
|
7
|
+
data.tar.gz: a567503b4d12425d0ca89931707c14a41ec8b026986a51ff18676042bec51d15eaac45171faf8d13edc3c49489f7ffea62294becc5d7221e31b78db5374a72e8
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Gem fixed_record Changelog
|
2
|
+
|
3
|
+
## 0.3.0
|
4
|
+
* Add optional required and optional arguments to specify required and optional fields respectively
|
5
|
+
|
6
|
+
## 0.2.0
|
7
|
+
* Add support for a Hash of Hashes in the YAML file, and for
|
8
|
+
accessing records by key.
|
9
|
+
* Added CHANGELOG.md
|
10
|
+
|
11
|
+
## 0.1.x
|
12
|
+
* Initial release
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -48,7 +48,7 @@ Then to load these, create a class
|
|
48
48
|
require 'fixed_record'
|
49
49
|
|
50
50
|
class MyFavoriteWebsite < FixedRecord
|
51
|
-
data "#{Rails.root}/data/my_favorite_websites.yml"
|
51
|
+
data "#{Rails.root}/data/my_favorite_websites.yml", required: [:name, :url]
|
52
52
|
|
53
53
|
# Return hostname of url for company
|
54
54
|
def hostname
|
@@ -88,7 +88,8 @@ StaticPage#first:
|
|
88
88
|
description: Welcome to the First Page
|
89
89
|
|
90
90
|
StaticPage#last:
|
91
|
-
title: Last Page
|
91
|
+
title: Last Page
|
92
|
+
short_title: LastP
|
92
93
|
description: Welcome to the Last Page
|
93
94
|
|
94
95
|
```
|
@@ -99,7 +100,7 @@ Then to load these, create a class
|
|
99
100
|
require 'fixed_record'
|
100
101
|
|
101
102
|
class MyWebPages < FixedRecord
|
102
|
-
data "#{Rails.root}/data/my_web_pages.yml"
|
103
|
+
data "#{Rails.root}/data/my_web_pages.yml", required: [:title,:description], optional: [:short_title]
|
103
104
|
|
104
105
|
end
|
105
106
|
```
|
@@ -140,12 +141,35 @@ The declared class will also include all the methods from the `Enumerable` modul
|
|
140
141
|
Some basic sanity checks are performed on the YAML file to catch common errors:
|
141
142
|
|
142
143
|
* It must define a non-empty array or hash of records
|
143
|
-
*
|
144
|
+
* If the optional `required:` or `optional:` arguments are given, then each record _must_ have all the required fields and _may_ also have any of the optional fields.
|
145
|
+
* If niether the `required:` or `optional:` arguments are given, then each record _must_ have the same set of fields.
|
146
|
+
|
147
|
+
An `ArgumentError` exception will be thrown if any validation errors are detected. A system-dependent error (probably `Errno::ENOENT`) will be thrown if the file cannot be read.
|
148
|
+
|
149
|
+
Additional validations can be performed by defining a `validate` method. e.g.
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
require 'fixed_record'
|
153
|
+
require 'uri'
|
154
|
+
|
155
|
+
class MyFavoriteWebsite < FixedRecord
|
156
|
+
data "#{Rails.root}/data/my_favorite_websites.yml", required: [:name, :url]
|
157
|
+
|
158
|
+
# Check that the url can be parsed
|
159
|
+
def validate( values, index )
|
160
|
+
begin
|
161
|
+
URI.parse(url)
|
162
|
+
rescue URI::InvalidURIError -> e
|
163
|
+
raise e.class, "#{filename} index #{index} has invalid url: #{e.message}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
|
144
171
|
|
145
|
-
An `ArgumentError` exception will be thrown if any errors are detected.
|
146
172
|
|
147
|
-
Additional validations can be performed by overriding the `validate_yaml` and
|
148
|
-
`validate_item` class functions.
|
149
173
|
|
150
174
|
|
151
175
|
## Development
|
data/lib/fixed_record.rb
CHANGED
@@ -1,21 +1,33 @@
|
|
1
1
|
|
2
2
|
require 'yaml'
|
3
|
+
require 'set'
|
3
4
|
|
4
5
|
class FixedRecord
|
5
|
-
VERSION = "0.
|
6
|
+
VERSION = "0.3.0"
|
6
7
|
|
7
8
|
# Lazy load data from given filename
|
8
9
|
# creating accessors for top level attributes
|
9
|
-
def self.data( filename )
|
10
|
+
def self.data( filename, required: [], optional: [] )
|
11
|
+
required = required.map( &:to_s )
|
12
|
+
optional = optional.map( &:to_s )
|
13
|
+
throw ArgumentError, "Required and Optional names overlap" unless (required & optional).empty?
|
14
|
+
|
15
|
+
valid_keys = Set.new( required )
|
16
|
+
valid_keys.merge( optional )
|
17
|
+
required_keys = Set.new( required )
|
18
|
+
|
19
|
+
self.class_variable_set( :@@filename, filename )
|
20
|
+
self.class_variable_set( :@@required_keys, required_keys )
|
21
|
+
self.class_variable_set( :@@valid_keys, valid_keys )
|
22
|
+
self.class_variable_set( :@@items, nil )
|
23
|
+
|
10
24
|
class_eval %Q{
|
11
25
|
class << self
|
12
26
|
include Enumerable
|
13
27
|
end
|
14
28
|
|
15
|
-
@@items = nil
|
16
|
-
|
17
29
|
def self.filename
|
18
|
-
|
30
|
+
@@filename
|
19
31
|
end
|
20
32
|
|
21
33
|
def self.all
|
@@ -50,47 +62,59 @@ class FixedRecord
|
|
50
62
|
def self.load!
|
51
63
|
if @@items.nil?
|
52
64
|
y = YAML.load_file( filename )
|
53
|
-
|
54
|
-
valid_keys = nil
|
65
|
+
validate_structure( y )
|
55
66
|
if y.is_a?(Array)
|
56
|
-
valid_keys
|
67
|
+
if @@valid_keys.empty?
|
68
|
+
@@valid_keys = y.first.keys
|
69
|
+
@@required_keys = @@valid_keys
|
70
|
+
end
|
57
71
|
@@items = y.map.with_index do |values,i|
|
58
|
-
validate_item( valid_keys, values, i )
|
72
|
+
validate_item( @@valid_keys, @@required_keys, values, i )
|
59
73
|
r = new
|
60
74
|
r.instance_variable_set( :@values, values )
|
61
75
|
r
|
62
76
|
end
|
63
77
|
elsif y.is_a?(Hash)
|
64
78
|
@@items = Hash.new
|
65
|
-
add_key =
|
79
|
+
add_key = !@@valid_keys.member?('key')
|
66
80
|
y.each do |k,values|
|
67
|
-
if valid_keys.
|
68
|
-
|
69
|
-
|
81
|
+
if @@valid_keys.empty?
|
82
|
+
@@required_keys.merge( values.keys )
|
83
|
+
@@valid_keys.merge( values.keys )
|
84
|
+
add_key = !@@valid_keys.member?('key')
|
70
85
|
end
|
71
|
-
validate_item( valid_keys, values, k )
|
86
|
+
validate_item( @@valid_keys, @@required_keys, values, k )
|
72
87
|
values['key'] = k if add_key
|
73
88
|
r = new
|
74
89
|
r.instance_variable_set( :@values, values )
|
75
90
|
@@items[k] = r
|
76
91
|
end
|
77
|
-
|
92
|
+
define_method( :key ) { @values['key'] } if add_key
|
78
93
|
end
|
79
|
-
create_methods( valid_keys
|
94
|
+
create_methods( @@valid_keys )
|
80
95
|
end
|
81
96
|
end
|
82
97
|
}
|
83
98
|
end
|
84
99
|
|
100
|
+
|
101
|
+
# Override this to perform additional entries. It gets passed the hash containing the
|
102
|
+
# values for each record. index is either a record index (0 based) or a key associated
|
103
|
+
# with the record
|
104
|
+
def self.validate( values, index )
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
85
109
|
# Create access methods for each of valid_keys
|
86
110
|
def self.create_methods( valid_keys )
|
87
|
-
valid_keys.each do |
|
88
|
-
define_method(
|
111
|
+
valid_keys.each do |key|
|
112
|
+
define_method( key.to_sym) { @values[key] }
|
89
113
|
end
|
90
114
|
end
|
91
115
|
|
92
116
|
# Validate the top level of the data structure returned
|
93
|
-
def self.
|
117
|
+
def self.validate_structure( y )
|
94
118
|
if y.is_a?(Array)
|
95
119
|
if y.length <= 0
|
96
120
|
throw ArgumentError.new "#{filename} contain a zero length array"
|
@@ -112,14 +136,16 @@ class FixedRecord
|
|
112
136
|
end
|
113
137
|
|
114
138
|
# Validate a values of name -> value
|
115
|
-
def self.validate_item( valid_keys, values, index )
|
139
|
+
def self.validate_item( valid_keys, required_keys, values, index )
|
116
140
|
raise ArgumentError, "#{filename} item #{index} should be name value pairs" unless values.is_a?(Hash)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
141
|
+
required_keys.each do |name|
|
142
|
+
raise ArgumentError, "#{filename} item #{index} is missing value for '#{name}'" unless values.has_key?(name)
|
143
|
+
end
|
144
|
+
values.keys.each do |v|
|
145
|
+
raise ArgumentError, "#{filename} item #{index} has unexpected value for '#{name}'" unless valid_keys.include?(v)
|
122
146
|
end
|
147
|
+
# User can implement this to add extra validation
|
148
|
+
validate( values, index )
|
123
149
|
end
|
124
150
|
|
125
151
|
|
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.3.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-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- ".gitignore"
|
63
63
|
- ".rspec"
|
64
64
|
- ".travis.yml"
|
65
|
+
- CHANGELOG.md
|
65
66
|
- Gemfile
|
66
67
|
- Gemfile.lock
|
67
68
|
- README.md
|