fixed_record 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|