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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0eea6e2937878d931df67a139cff38882002163f62f43e9f6b4e9440c84bbc60
4
- data.tar.gz: 8d51b0834f97783271b77fd8762289efad419c463aa3a6f705affded0a07de2e
3
+ metadata.gz: 156863124ec2fb0ca1668bafa2b16de94d622f577ea554ace2189dd24758bfa4
4
+ data.tar.gz: caf2f4fb5e63bd96218dc25eeeda8ede9bf792acc35bebb992aecb2068a395de
5
5
  SHA512:
6
- metadata.gz: 39687e91690bd8426119d2c41b77298dc3a48c2da4000a57bc6160f14ea2eb021d4495eac2ca27d50189fa5fcedbb2196c4c543bda44ff936aba2cf27d4f9b42
7
- data.tar.gz: '0697f532ce75a0e808fefe5a94a9fa42b9fa00e346c7e6dda1288066aab857ab36d196a57473134d04d66ad4aa0b4b91a4db57a8197284a5c49ff9cfaf18b432'
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fixed_record (0.2.0)
4
+ fixed_record (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- * All records must have the same set of attributes
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.2.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
- %Q{#{filename}}
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
- validate_yaml( y )
54
- valid_keys = nil
65
+ validate_structure( y )
55
66
  if y.is_a?(Array)
56
- valid_keys = y.first.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 = true
79
+ add_key = !@@valid_keys.member?('key')
66
80
  y.each do |k,values|
67
- if valid_keys.nil?
68
- valid_keys = values.keys
69
- add_key = !values.has_key?('key')
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
- valid_keys << 'key' if add_key
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 |k|
88
- define_method( k.to_sym) { @values[k] }
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.validate_yaml( y )
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
- 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}'"
121
- end
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.2.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-22 00:00:00.000000000 Z
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