rod 0.7.1 → 0.7.2

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.
Files changed (76) hide show
  1. data/.travis.yml +1 -1
  2. data/README.rdoc +38 -10
  3. data/Rakefile +20 -9
  4. data/changelog.txt +25 -0
  5. data/contributors.txt +1 -0
  6. data/data/backward/0.7.0/_join_element.dat +0 -0
  7. data/data/backward/0.7.0/_polymorphic_join_element.dat +0 -0
  8. data/data/backward/0.7.0/char.dat +0 -0
  9. data/data/backward/0.7.0/database.yml +58 -0
  10. data/data/backward/0.7.0/rod_test__automobile.dat +0 -0
  11. data/data/backward/0.7.0/rod_test__caveman.dat +0 -0
  12. data/data/backward/0.7.0/rod_test__dog.dat +0 -0
  13. data/data/backward/0.7.0/rod_test__test_model.dat +0 -0
  14. data/data/portability/_join_element.dat +0 -0
  15. data/data/portability/_polymorphic_join_element.dat +0 -0
  16. data/data/portability/char.dat +0 -0
  17. data/data/portability/database.yml +49 -0
  18. data/data/portability/rod_test__automobile.dat +0 -0
  19. data/data/portability/rod_test__caveman.dat +0 -0
  20. data/data/portability/rod_test__dog.dat +0 -0
  21. data/data/portability/rod_test__test_model.dat +0 -0
  22. data/features/backward.feature +33 -0
  23. data/features/basic.feature +3 -0
  24. data/features/collection_proxy.feature +95 -0
  25. data/features/flat_indexing.feature +44 -2
  26. data/features/hash_indexing.feature +63 -9
  27. data/features/portability.feature +72 -0
  28. data/features/segmented_indexing.feature +45 -2
  29. data/features/steps/collection_proxy.rb +1 -1
  30. data/features/steps/model.rb +48 -5
  31. data/features/steps/rod.rb +15 -16
  32. data/lib/rod.rb +11 -1
  33. data/lib/rod/abstract_database.rb +52 -42
  34. data/lib/rod/berkeley/collection_proxy.rb +96 -0
  35. data/lib/rod/berkeley/database.rb +337 -0
  36. data/lib/rod/berkeley/environment.rb +209 -0
  37. data/lib/rod/berkeley/sequence.rb +222 -0
  38. data/lib/rod/berkeley/transaction.rb +233 -0
  39. data/lib/rod/collection_proxy.rb +76 -1
  40. data/lib/rod/constants.rb +3 -2
  41. data/lib/rod/database.rb +127 -14
  42. data/lib/rod/index/base.rb +12 -3
  43. data/lib/rod/index/hash_index.rb +295 -70
  44. data/lib/rod/index/segmented_index.rb +3 -0
  45. data/lib/rod/model.rb +154 -531
  46. data/lib/rod/property/base.rb +190 -0
  47. data/lib/rod/property/field.rb +258 -0
  48. data/lib/rod/property/plural_association.rb +145 -0
  49. data/lib/rod/property/singular_association.rb +139 -0
  50. data/rod.gemspec +6 -4
  51. data/spec/berkeley/database.rb +83 -0
  52. data/spec/berkeley/environment.rb +58 -0
  53. data/spec/berkeley/sequence.rb +101 -0
  54. data/spec/berkeley/transaction.rb +92 -0
  55. data/spec/collection_proxy.rb +38 -0
  56. data/spec/database.rb +36 -0
  57. data/spec/model.rb +26 -0
  58. data/spec/property/base.rb +73 -0
  59. data/spec/property/field.rb +244 -0
  60. data/spec/property/plural_association.rb +67 -0
  61. data/spec/property/singular_association.rb +65 -0
  62. data/tests/class_compatibility_create.rb +2 -2
  63. data/tests/eff1_test.rb +1 -1
  64. data/tests/eff2_test.rb +1 -1
  65. data/tests/full_runs.rb +1 -1
  66. data/tests/generate_classes_create.rb +14 -14
  67. data/tests/migration_create.rb +47 -47
  68. data/tests/migration_verify.rb +1 -1
  69. data/tests/missing_class_create.rb +6 -6
  70. data/tests/properties_order_create.rb +4 -4
  71. data/tests/read_on_create.rb +33 -34
  72. data/tests/save_struct.rb +40 -39
  73. data/tests/unit/database.rb +1 -1
  74. data/tests/unit/model_tests.rb +73 -65
  75. metadata +71 -15
  76. data/tests/unit/model.rb +0 -36
@@ -0,0 +1,190 @@
1
+ require 'rod/exception'
2
+ require 'rod/constants'
3
+
4
+ module Rod
5
+ module Property
6
+ # This class defines the properties which are used in Rod::Model.
7
+ # These might be:
8
+ # * fields
9
+ # * has_one associations
10
+ # * has_many associations
11
+ # It provides basic data concerning these properties, such as name,
12
+ # options, etc.
13
+ class Base
14
+ # The name of the property.
15
+ attr_reader :name
16
+
17
+ # The options of the property.
18
+ attr_reader :options
19
+
20
+ # Initializes the property associated with +klass+
21
+ # with its +name+ and +options+.
22
+ def initialize(klass,name,options)
23
+ check_class(klass)
24
+ @klass = klass
25
+ check_name(name)
26
+ @name = name
27
+ check_options(options)
28
+ @options = options.dup.freeze
29
+ end
30
+
31
+ # Checks the difference in options between this and the +other+
32
+ # property. The prefix of legacy module is removed from the
33
+ # values of the options.
34
+ def difference(other)
35
+ self_options = {}
36
+ self.options.each{|k,v| self_options[k] = v.to_s.sub(LEGACY_RE,"")}
37
+ other_options = {}
38
+ other.options.each{|k,v| other_options[k] = v.to_s.sub(LEGACY_RE,"")}
39
+ differences = {}
40
+ self_options.each do |option,value|
41
+ if other_options[option] != value
42
+ differences[option] = [value,other_options[option]]
43
+ end
44
+ end
45
+ other_options.each do |option,value|
46
+ if self_options[option] != value && !differences.has_key?(option)
47
+ differences[option] = [self_options[option],value]
48
+ end
49
+ end
50
+ differences
51
+ end
52
+
53
+ # Returns the index associated with the property.
54
+ def index
55
+ @index ||= Index::Base.create(path(@klass.database.path),@klass,@options)
56
+ end
57
+
58
+ # Returns true if the property has an index.
59
+ def has_index?
60
+ !@options[:index].nil?
61
+ end
62
+
63
+ # Get rid of the index that is associated with this property.
64
+ def reset_index
65
+ @index = nil
66
+ end
67
+
68
+ # Creates a copy of the property with a new +klass+.
69
+ def copy(klass)
70
+ self.class.new(klass,@name,@options)
71
+ end
72
+
73
+ # Defines finders (+find_by+ and +find_all_by+) for indexed property.
74
+ def define_finders
75
+ return unless has_index?
76
+ # optimization
77
+ name = @name.to_s
78
+ property = self
79
+ (class << @klass; self; end).class_eval do
80
+ # Find all objects with given +value+ of the +property+.
81
+ define_method("find_all_by_#{name}") do |value|
82
+ property.index[value]
83
+ end
84
+
85
+ # Find first object with given +value+ of the +property+.
86
+ define_method("find_by_#{name}") do |value|
87
+ property.index[value][0]
88
+ end
89
+ end
90
+ end
91
+
92
+ protected
93
+ # The name of the file or directory (for given +relative_path+), where
94
+ # the data of the property (e.g. index) is stored.
95
+ def path(relative_path)
96
+ "#{relative_path}#{@klass.model_path}_#{@name}"
97
+ end
98
+
99
+ # Checks if the property +name+ is valid.
100
+ def check_name(name)
101
+ if !name.is_a?(Symbol) || name.to_s.empty? || INVALID_NAMES.has_key?(name)
102
+ raise InvalidArgument.new(name,"property name")
103
+ end
104
+ end
105
+
106
+ # Checks if the +klass+ is valid class for the property.
107
+ def check_class(klass)
108
+ raise InvalidArgument.new(klass,"class") if klass.nil?
109
+ end
110
+
111
+ # Reads the value of a field +name+ of the C struct +struct_name+
112
+ # that corresponds to given Ruby object. The C +result_type+
113
+ # of the result has to be specified.
114
+ def field_reader(name,struct_name,result_type,builder)
115
+ str =<<-END
116
+ |#{result_type} _#{name}(unsigned long object_rod_id){
117
+ | VALUE klass;
118
+ | #{struct_name} * pointer;
119
+ | uint64_t as_uint;
120
+ | uint64_t result_swapped;
121
+ |
122
+ | if(object_rod_id == 0){
123
+ | rb_raise(rodException(), "Invalid object rod_id (0)");
124
+ | }
125
+ | klass = rb_funcall(self,rb_intern("class"),0);
126
+ | pointer = (#{struct_name} *)
127
+ | NUM2ULONG(rb_funcall(klass,rb_intern("rod_pointer"),0));
128
+ |#ifdef __BYTE_ORDER
129
+ |# if __BYTE_ORDER == __BIG_ENDIAN
130
+ | // This code assumes that all values are 64 bit wide. This is not true
131
+ | // on 32-bit systems but is addressed in #221
132
+ | as_uint = (pointer + object_rod_id - 1)->#{name};
133
+ | result_swapped = bswap_64(*((uint64_t *)((char *)&as_uint)));
134
+ | return *(#{result_type} *)((char *)&result_swapped);
135
+ |# else
136
+ | return (pointer + object_rod_id - 1)->#{name};
137
+ |# endif
138
+ |#else
139
+ | return (pointer + object_rod_id - 1)->#{name};
140
+ |#endif
141
+ |}
142
+ END
143
+ builder.c(str.margin)
144
+ end
145
+
146
+ # Writes the value of a field +name+ of the C struct +struct_name+
147
+ # that corresponds to given Ruby object. The C +arg_type+
148
+ # of the argument has to be specified.
149
+ def field_writer(name,struct_name,arg_type,builder)
150
+ str =<<-END
151
+ |void _#{name}_equals(unsigned long object_rod_id,#{arg_type} value){
152
+ | VALUE klass;
153
+ | #{struct_name} * pointer;
154
+ | uint64_t value_swapped;
155
+ |
156
+ | if(object_rod_id == 0){
157
+ | rb_raise(rodException(), "Invalid object rod_id (0)");
158
+ | }
159
+ | klass = rb_funcall(self,rb_intern("class"),0);
160
+ | pointer = (#{struct_name} *)
161
+ | NUM2ULONG(rb_funcall(klass,rb_intern("rod_pointer"),0));
162
+ |#ifdef __BYTE_ORDER
163
+ |# if __BYTE_ORDER == __BIG_ENDIAN
164
+ | // TODO #220 #221
165
+ | value_swapped = bswap_64(*((uint64_t *)((char *)&value)));
166
+ | (pointer + object_rod_id - 1)->#{name} = value_swapped;
167
+ |# else
168
+ | (pointer + object_rod_id - 1)->#{name} = value;
169
+ |# endif
170
+ |#else
171
+ | (pointer + object_rod_id - 1)->#{name} = value;
172
+ |#endif
173
+ |}
174
+ END
175
+ builder.c(str.margin)
176
+ end
177
+
178
+ # Returns the size of the C type.
179
+ def sizeof(type)
180
+ # TODO implement
181
+ 0
182
+ end
183
+
184
+ # Returns the C type for given Rod type.
185
+ def c_type(type)
186
+ TYPE_MAPPING[type]
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,258 @@
1
+ require 'rod/property/base'
2
+ require 'rod/constants'
3
+ require 'json'
4
+
5
+ module Rod
6
+ module Property
7
+ # This class defines the field property.
8
+ # A field has to define its +name+ and its +type+.
9
+ class Field < Base
10
+ # The type of the property.
11
+ attr_reader :type
12
+
13
+ # The valid types of fields.
14
+ VALID_TYPES = [:string, :integer, :float, :ulong, :object, :json]
15
+
16
+ # The fields with variable size.
17
+ VARIABLE_TYPES = [:string, :object, :json]
18
+
19
+ # The name of the field used to identify the objects.
20
+ IDENTIFIER = :rod_id
21
+
22
+ # Initialize the field associated with the +klass+ with +name+, +type+ and +options+.
23
+ # The type should be one of:
24
+ # * +:integer+
25
+ # * +:ulong+
26
+ # * +:float+
27
+ # * +:string+
28
+ # * +:object+ (value is marshaled durign storage, and unmarshaled during read)
29
+ # * +:json+ (value is dumped in JSON format during storage, and loaded during read.
30
+ # Note: some Ruby types are not unified during conversion, e.g. String and Symbol)
31
+ # The valid options are:
32
+ # * +:index+ builds an index for the field and might be:
33
+ # ** +:flat+ simple hash index (+true+ works as well for backwards compatiblity)
34
+ # ** +:segmented+ index split for 1001 pieces for shorter load times (only
35
+ # one piece is loaded on one look-up)
36
+ def initialize(klass,name,type,options={})
37
+ super(klass,name,options)
38
+ check_type(type)
39
+ @type = type
40
+ end
41
+
42
+ # Creates a copy of the field with a new +klass+.
43
+ def copy(klass)
44
+ self.class.new(klass,@name,@type,@options)
45
+ end
46
+
47
+ # Predicate indicating that this property is a field.
48
+ def field?
49
+ true
50
+ end
51
+
52
+ # Predicate indicating that this property is not an association.
53
+ def association?
54
+ false
55
+ end
56
+
57
+ # Returns the default value for given type of field.
58
+ def default_value
59
+ case @type
60
+ when :integer
61
+ 0
62
+ when :ulong
63
+ 0
64
+ when :float
65
+ 0.0
66
+ when :string
67
+ ''
68
+ when :object, :json
69
+ nil
70
+ end
71
+ end
72
+
73
+ # Returns true if the field has a variable size.
74
+ def variable_size?
75
+ VARIABLE_TYPES.include?(@type)
76
+ end
77
+
78
+ # Dumps the +value+ of the field according to its type.
79
+ def dump(value)
80
+ case @type
81
+ when :object
82
+ Marshal.dump(value)
83
+ when :json
84
+ JSON.dump([value])
85
+ when :string
86
+ # TODO the encoding should be stored in the DB
87
+ # or configured globally
88
+ value.encode("utf-8")
89
+ when :ulong
90
+ raise InvalidArgument.new(value,"ulong") if value < 0
91
+ value
92
+ else
93
+ value
94
+ end
95
+ end
96
+
97
+ # Loads the +value+ of the field according to its type.
98
+ def load(value)
99
+ return value unless variable_size?
100
+ case @type
101
+ when :object
102
+ value.force_encoding("ascii-8bit")
103
+ value = Marshal.load(value) rescue nil
104
+ when :json
105
+ value.force_encoding("ascii-8bit")
106
+ value = JSON.load(value).first rescue nil
107
+ when :string
108
+ value.force_encoding("utf-8")
109
+ end
110
+ value
111
+ end
112
+
113
+ # Returns true if the field is used to identify the objects.
114
+ def identifier?
115
+ @name == IDENTIFIER
116
+ end
117
+
118
+ # Returns the metadata of the field in form of a hash.
119
+ def metadata
120
+ @options.merge({:type => @type})
121
+ end
122
+
123
+ # Converts the field to fields in a C struct.
124
+ def to_c_struct
125
+ unless variable_size?
126
+ str = <<-SUBEND
127
+ |#ifdef __BYTE_ORDER
128
+ |# if __BYTE_ORDER == __BIG_ENDIAN
129
+ | uint64_t #{@name};
130
+ |# else
131
+ | #{c_type(@type)} #{@name};
132
+ |# endif
133
+ |#else
134
+ | #{c_type(@type)} #{@name};
135
+ |#endif
136
+ SUBEND
137
+ str.margin
138
+ else
139
+ " #{c_type(:ulong)} #{@name}_length;\n" +
140
+ " #{c_type(:ulong)} #{@name}_offset;\n"
141
+ end
142
+ end
143
+
144
+ # Defines the accessor of the field's constituents
145
+ # (C struct field/fields that hold the field data).
146
+ def define_c_accessors(builder)
147
+ unless variable_size?
148
+ field_reader(@name,@klass.struct_name,c_type(@type),builder)
149
+ field_writer(@name,@klass.struct_name,c_type(@type),builder)
150
+ else
151
+ field_reader("#{@name}_length",@klass.struct_name,c_type(:ulong),builder)
152
+ field_reader("#{@name}_offset",@klass.struct_name,c_type(:ulong),builder)
153
+ field_writer("#{@name}_length",@klass.struct_name,c_type(:ulong),builder)
154
+ field_writer("#{@name}_offset",@klass.struct_name,c_type(:ulong),builder)
155
+ end
156
+ end
157
+
158
+ # Make the C accessors private.
159
+ def seal_c_accessors
160
+ unless variable_size?
161
+ @klass.send(:private,"_#{@name}")
162
+ @klass.send(:private,"_#{@name}=")
163
+ else
164
+ @klass.send(:private,"_#{@name}_length")
165
+ @klass.send(:private,"_#{@name}_length=")
166
+ @klass.send(:private,"_#{@name}_offset")
167
+ @klass.send(:private,"_#{@name}_offset=")
168
+ end
169
+ end
170
+
171
+ # Defines the getter of the Ruby class which corresponds to this field.
172
+ def define_getter
173
+ field = @name.to_s
174
+ unless variable_size?
175
+ @klass.send(:define_method,field) do
176
+ value = instance_variable_get("@#{field}")
177
+ if value.nil?
178
+ if self.new?
179
+ value = nil
180
+ else
181
+ value = send("_#{field}",@rod_id)
182
+ end
183
+ instance_variable_set("@#{field}",value)
184
+ end
185
+ value
186
+ end
187
+ else
188
+ is_object = @type != :string
189
+ type = @type
190
+ property = self
191
+ database = @klass.database
192
+ @klass.send(:define_method,field) do
193
+ value = instance_variable_get("@#{field}")
194
+ if value.nil? # first call
195
+ if self.new?
196
+ return (is_object ? nil : "")
197
+ else
198
+ length = send("_#{field}_length", @rod_id)
199
+ if length == 0
200
+ return (is_object ? nil : "")
201
+ end
202
+ offset = send("_#{field}_offset", @rod_id)
203
+ read_options = {}
204
+ if is_object
205
+ read_options[:skip_encoding] = true
206
+ end
207
+ value = database.read_string(length, offset)
208
+ value = property.load(value)
209
+ # caching Ruby representation
210
+ # don't use setter - avoid change tracking
211
+ instance_variable_set("@#{field}",value)
212
+ end
213
+ end
214
+ value
215
+ end
216
+ end
217
+ end
218
+
219
+ # Defines the settor of the Ruby class which corresponds to this field.
220
+ def define_setter
221
+ # optimization
222
+ field = @name.to_s
223
+ @klass.send(:define_method,"#{field}=") do |value|
224
+ old_value = send(field)
225
+ send("#{field}_will_change!") unless old_value == value
226
+ instance_variable_set("@#{field}",value)
227
+ value
228
+ end
229
+ end
230
+
231
+ # Returns the memory layout of the C struct fields that
232
+ # correspond to this field.
233
+ def layout
234
+ unless variable_size?
235
+ "#{@name}[value:#{sizeof(@type)}]"
236
+ else
237
+ "#{@name}[length:#{sizeof(:ulong)}+" +
238
+ "offset:#{sizeof(:ulong)}]"
239
+ end
240
+ end
241
+
242
+ protected
243
+ # Check if the property has a valid type.
244
+ # An exceptions is raised if the type is invalid.
245
+ def check_type(type)
246
+ unless VALID_TYPES.include?(type)
247
+ raise InvalidArgument.new(type,"field type")
248
+ end
249
+ end
250
+
251
+ # Check if the property has valid options.
252
+ # An exceptions is raised if they are not.
253
+ def check_options(options)
254
+ #TODO implement
255
+ end
256
+ end
257
+ end
258
+ end
@@ -0,0 +1,145 @@
1
+ require 'rod/property/base'
2
+
3
+ module Rod
4
+ module Property
5
+ # This class defines the +has_many+ (plural association) property.
6
+ # A +has_many+ property has to define its +name+.
7
+ class PluralAssociation < Base
8
+ # Creates new plural association associated with +klass+
9
+ # with given +name+ and +options+.
10
+ def initialize(klass,name,options={})
11
+ super(klass,name,options)
12
+ end
13
+
14
+ # Predicate indicating that this property is a field.
15
+ def field?
16
+ false
17
+ end
18
+
19
+ # Predicate indicating that this property is an association.
20
+ def association?
21
+ true
22
+ end
23
+
24
+ # Predicate indicating that this property is not a singular association.
25
+ def singular?
26
+ false
27
+ end
28
+
29
+ # Predicate indicating that this property is a plural association.
30
+ def plural?
31
+ true
32
+ end
33
+
34
+ # Predicate indicating that this property is polymorphic.
35
+ def polymorphic?
36
+ @options[:polymorphic]
37
+ end
38
+
39
+ # Returns the metadata of the association in form of a hash.
40
+ def metadata
41
+ @options.dup
42
+ end
43
+
44
+ # Converts the association to fields in a C struct.
45
+ def to_c_struct
46
+ " #{c_type(:ulong)} #{@name}_offset;\n" +
47
+ " #{c_type(:ulong)} #{@name}_count;\n"
48
+ end
49
+
50
+ # Defines the accessor of the association's constituents
51
+ # (C struct field/fields that hold the association data).
52
+ def define_c_accessors(builder)
53
+ field_reader("#{@name}_count",@klass.struct_name,c_type(:ulong),builder)
54
+ field_reader("#{@name}_offset",@klass.struct_name,c_type(:ulong),builder)
55
+ field_writer("#{@name}_count",@klass.struct_name,c_type(:ulong),builder)
56
+ field_writer("#{@name}_offset",@klass.struct_name,c_type(:ulong),builder)
57
+ end
58
+
59
+ # Make the C accessors private.
60
+ def seal_c_accessors
61
+ @klass.private "_#{@name}_count"
62
+ @klass.private "_#{@name}_count="
63
+ @klass.private "_#{@name}_offset"
64
+ @klass.private "_#{@name}_offset="
65
+ end
66
+
67
+ # Make the C accessors private.
68
+ def seal_c_accessors
69
+ @klass.send(:private,"_#{@name}_count")
70
+ @klass.send(:private,"_#{@name}_count=")
71
+ @klass.send(:private,"_#{@name}_offset")
72
+ @klass.send(:private,"_#{@name}_offset=")
73
+ end
74
+
75
+ # Defines the getter of the Ruby class which corresponds to this association.
76
+ def define_getter
77
+ # optimization
78
+ name = @name.to_s
79
+ class_name =
80
+ if options[:class_name]
81
+ options[:class_name]
82
+ else
83
+ "#{@klass.scope_name}::#{::English::Inflect.singular(name).camelcase}"
84
+ end
85
+ klass = options[:polymorphic] ? nil : class_name.constantize
86
+ database = @klass.database
87
+ @klass.send(:define_method,"#{name}") do
88
+ proxy = instance_variable_get("@#{name}")
89
+ if proxy.nil?
90
+ if self.new?
91
+ count = 0
92
+ offset = 0
93
+ else
94
+ count = self.send("_#{name}_count",@rod_id)
95
+ offset = self.send("_#{name}_offset",@rod_id)
96
+ end
97
+ proxy = CollectionProxy.new(count,database,offset,klass)
98
+ instance_variable_set("@#{name}", proxy)
99
+ end
100
+ proxy
101
+ end
102
+ # count getter
103
+ @klass.send(:define_method,"#{name}_count") do
104
+ if (instance_variable_get("@#{name}") != nil)
105
+ return instance_variable_get("@#{name}").count
106
+ else
107
+ if self.new?
108
+ return 0
109
+ else
110
+ return send("_#{name}_count",@rod_id)
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ # Defines the settor of the Ruby class which corresponds to this association.
117
+ def define_setter
118
+ # optimization
119
+ name = @name.to_s
120
+ @klass.send(:define_method,"#{name}=") do |value|
121
+ proxy = send(name)
122
+ proxy.clear
123
+ value.each do |object|
124
+ proxy << object
125
+ end
126
+ proxy
127
+ end
128
+ end
129
+
130
+ # Returns the memory layout of the C struct fields that
131
+ # correspond to this association.
132
+ def layout
133
+ "#{@name}[offset:#{sizeof(:ulong)}+" +
134
+ "count:#{sizeof(:ulong)}]"
135
+ end
136
+
137
+ protected
138
+ # Check if the property has valid options.
139
+ # An exceptions is raised if they are not.
140
+ def check_options(options)
141
+ #TODO implement
142
+ end
143
+ end
144
+ end
145
+ end