degu 0.0.4

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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .*.sw[pon]
2
+ .DS_Store
3
+ .rvmrc
4
+ Gemfile.lock
5
+ coverage
6
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # vim: set filetype=ruby et sw=2 ts=2:
2
+
3
+ source :rubygems
4
+
5
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,150 @@
1
+ = Degu
2
+
3
+ Degu bundles the renum Enumeration implementation with the has_enum and has_set
4
+ rails plugins.
5
+
6
+ == Renum
7
+
8
+ === Description
9
+
10
+ Renum provides a readable but terse enum facility for Ruby. Enums are
11
+ sometimes called object constants and are analogous to the type-safe enum
12
+ pattern in Java, though obviously Ruby's flexibility means there's no such
13
+ thing as type-safety.
14
+
15
+ == Usage
16
+
17
+ Renum allows you to do things like this:
18
+
19
+ enum :Status, %w( NOT_STARTED IN_PROGRESS COMPLETE )
20
+
21
+ enum :Size do
22
+ Small("Really really tiny")
23
+ Medium("Sort of in the middle")
24
+ Large("Quite big")
25
+
26
+ attr_reader :description
27
+
28
+ def init description
29
+ @description = description
30
+ end
31
+ end
32
+
33
+ module MyNamespace
34
+ enum :FooValue, [ :Bar, :Baz, :Bat ]
35
+ end
36
+
37
+ Giving you something that satisfies this spec, plus a bit more:
38
+
39
+ describe "enum" do
40
+
41
+ it "creates a class for the value type" do
42
+ Status.class.should == Class
43
+ end
44
+
45
+ it "makes each value an instance of the value type" do
46
+ Status::NOT_STARTED.class.should == Status
47
+ end
48
+
49
+ it "exposes array of values" do
50
+ Status.values.should == [Status::NOT_STARTED, Status::IN_PROGRESS, Status::COMPLETE]
51
+ end
52
+
53
+ it "provides an alternative means of declaring values where extra information can be provided for initialization" do
54
+ Size::Small.description.should == "Really really tiny"
55
+ end
56
+
57
+ it "enumerates over values" do
58
+ Status.map {|s| s.name}.should == %w[NOT_STARTED IN_PROGRESS COMPLETE]
59
+ end
60
+
61
+ it "indexes values" do
62
+ Status[2].should == Status::COMPLETE
63
+ end
64
+
65
+ it "provides index lookup on values" do
66
+ Status::IN_PROGRESS.index.should == 1
67
+ end
68
+
69
+ it "provides a reasonable to_s for values" do
70
+ Status::NOT_STARTED.to_s.should == "Status::NOT_STARTED"
71
+ end
72
+
73
+ it "makes values comparable" do
74
+ Status::NOT_STARTED.should < Status::COMPLETE
75
+ end
76
+
77
+ it "allows enums to be nested in other modules or classes" do
78
+ MyNamespace::FooValue::Bar.class.should == MyNamespace::FooValue
79
+ end
80
+
81
+ end
82
+
83
+ === Rails[http://www.rubyonrails.com/] Integration
84
+
85
+ To use enumerated values as ActiveRecord attribute values, use the
86
+ constantize_attribute plugin
87
+ (https://github.com/duelinmarkers/constantize_attribute/tree) (also by me).
88
+
89
+ class Vehicle < ActiveRecord::Base
90
+ enum :Status do
91
+ New()
92
+ Used()
93
+ Salvage(true)
94
+
95
+ def init(warn = false)
96
+ @warn = warn
97
+ end
98
+
99
+ def requires_warning_buyer?
100
+ @warn
101
+ end
102
+ end
103
+
104
+ constantize_attribute :status
105
+
106
+ end
107
+
108
+ v = Vehicle.create! :status => Vehicle::Status::New
109
+ # Now the database has the string "Vehicle::Status::New",
110
+ # but your record object exposes the Status object:
111
+ v.status.requires_warning_buyer? # => false
112
+
113
+ v.update_attribute :status, Vehicle::Status::Salvage
114
+ # Now the database has the string "Vehicle::Status::Salvage".
115
+ v.status.requires_warning_buyer? # => true
116
+
117
+ # Since constantize_attribute also accepts strings, it's easy
118
+ # to use enumerated values with forms.
119
+ v.status = "Vehicle::Status::Used"
120
+ v.status.requires_warning_buyer? # => false
121
+
122
+ === License
123
+
124
+ This code is free to use under the terms of the MIT license.
125
+
126
+ Permission is hereby granted, free of charge, to any person obtaining
127
+ a copy of this software and associated documentation files (the
128
+ "Software"), to deal in the Software without restriction, including
129
+ without limitation the rights to use, copy, modify, merge, publish,
130
+ distribute, sublicense, and/or sell copies of the Software, and to
131
+ permit persons to whom the Software is furnished to do so, subject to
132
+ the following conditions:
133
+
134
+ The above copyright notice and this permission notice shall be
135
+ included in all copies or substantial portions of the Software.
136
+
137
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
138
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
139
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
140
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
141
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
142
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
143
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
144
+
145
+ === Contact
146
+
147
+ Renum was created by John D. Hume. Comments are welcome. Send an email to
148
+ duelin dot markers at gmail or "contact me via my
149
+ blog[http://elhumidor.blogspot.com/].
150
+
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ # vim: set filetype=ruby et sw=2 ts=2:
2
+
3
+ require 'rspec'
4
+ require 'gem_hadar'
5
+
6
+ GemHadar do
7
+ name 'degu'
8
+ author 'Florian Frank'
9
+ email 'dev@pkw.de'
10
+ homepage "http://github.com/caroo/#{name}"
11
+ summary 'Library for enums and bitfield sets.'
12
+ description 'Library that includes enums, and rails support for enums and bitfield sets.'
13
+ test_dir 'test'
14
+ test_files Dir['test/**/*_test.rb']
15
+ spec_dir 'spec'
16
+ ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.rvmrc', 'coverage', '.DS_Store'
17
+ readme 'README.rdoc'
18
+
19
+ dependency 'activerecord', '~> 3.0'
20
+
21
+ development_dependency 'mocha'
22
+ development_dependency 'sqlite3'
23
+ development_dependency 'rspec'
24
+ end
25
+
26
+ desc 'Run specs and tests'
27
+ task :default => [ :test, :spec ]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
data/degu.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "degu"
5
+ s.version = "0.0.4"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Florian Frank"]
9
+ s.date = "2011-12-08"
10
+ s.description = "Library that includes enums, and rails support for enums and bitfield sets."
11
+ s.email = "dev@pkw.de"
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/degu/has_enum.rb", "lib/degu/has_set.rb", "lib/degu/polite.rb", "lib/degu/renum/enumerated_value.rb", "lib/degu/renum/enumerated_value_type_factory.rb", "lib/degu/renum.rb", "lib/degu/rude.rb", "lib/degu/version.rb", "lib/degu.rb"]
13
+ s.files = [".gitignore", "Gemfile", "README.rdoc", "Rakefile", "VERSION", "degu.gemspec", "lib/degu.rb", "lib/degu/has_enum.rb", "lib/degu/has_set.rb", "lib/degu/polite.rb", "lib/degu/renum.rb", "lib/degu/renum/enumerated_value.rb", "lib/degu/renum/enumerated_value_type_factory.rb", "lib/degu/rude.rb", "lib/degu/version.rb", "spec/renum_spec.rb", "spec/spec_helper.rb", "test/has_enum_test.rb", "test/has_set_test.rb", "test/test_helper.rb", "test_helper.rb"]
14
+ s.homepage = "http://github.com/caroo/degu"
15
+ s.rdoc_options = ["--title", "Degu - Library for enums and bitfield sets.", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubygems_version = "1.8.11"
18
+ s.summary = "Library for enums and bitfield sets."
19
+ s.test_files = ["test/has_enum_test.rb", "test/has_set_test.rb"]
20
+
21
+ if s.respond_to? :specification_version then
22
+ s.specification_version = 3
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_development_dependency(%q<gem_hadar>, ["~> 0.1.3"])
26
+ s.add_development_dependency(%q<mocha>, [">= 0"])
27
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
28
+ s.add_development_dependency(%q<rspec>, [">= 0"])
29
+ s.add_runtime_dependency(%q<activerecord>, ["~> 3.0"])
30
+ else
31
+ s.add_dependency(%q<gem_hadar>, ["~> 0.1.3"])
32
+ s.add_dependency(%q<mocha>, [">= 0"])
33
+ s.add_dependency(%q<sqlite3>, [">= 0"])
34
+ s.add_dependency(%q<rspec>, [">= 0"])
35
+ s.add_dependency(%q<activerecord>, ["~> 3.0"])
36
+ end
37
+ else
38
+ s.add_dependency(%q<gem_hadar>, ["~> 0.1.3"])
39
+ s.add_dependency(%q<mocha>, [">= 0"])
40
+ s.add_dependency(%q<sqlite3>, [">= 0"])
41
+ s.add_dependency(%q<rspec>, [">= 0"])
42
+ s.add_dependency(%q<activerecord>, ["~> 3.0"])
43
+ end
44
+ end
@@ -0,0 +1,79 @@
1
+ require "degu/renum"
2
+
3
+ module Degu
4
+ module HasEnum
5
+ def self.included(modul)
6
+ modul.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ # Use like this
12
+ #
13
+ # class Furniture
14
+ # has_enum :colors, :column_name => :custom_color_type
15
+ # end
16
+ def has_enum(enum_name, options={})
17
+
18
+ enum_column = options.has_key?(:column_name) ? options[:column_name].to_s : "#{enum_name}_type"
19
+
20
+ self.send("validate", "#{enum_column}_check_for_valid_type_of_enum")
21
+
22
+ # throws a NameError if Enum Class doesn't exists
23
+ enum_class = options.has_key?(:class_name) ? options[:class_name].to_s.constantize : enum_name.to_s.camelize.constantize
24
+
25
+ # Enum must be a Renum::EnumeratedValue Enum
26
+ raise ArgumentError, "expected Renum::EnumeratedValue" unless enum_class.superclass == Renum::EnumeratedValue
27
+
28
+ define_method("reset_enum_changed") do
29
+ @enum_changed = false
30
+ end
31
+ after_save :reset_enum_changed
32
+
33
+ define_method("#{enum_name}") do
34
+ begin
35
+ return self[enum_column].present? ? enum_class.const_get(self[enum_column]) : nil
36
+ rescue NameError => e
37
+ return nil
38
+ end
39
+ end
40
+
41
+ define_method("#{enum_column}=") do |enum_literal|
42
+ unless enum_literal == self[enum_column]
43
+ self[enum_column] = enum_literal
44
+ @enum_changed = true
45
+ end
46
+ end
47
+
48
+ define_method("#{enum_name}=") do |enum_to_set|
49
+ old_value = self[enum_column]
50
+ enum_resolved = enum_class[enum_to_set]
51
+ if enum_to_set.to_s.strip.empty?
52
+ self[enum_column] = nil
53
+ elsif enum_resolved
54
+ self[enum_column] = enum_resolved.name
55
+ else
56
+ raise ArgumentError, "could not resolve #{enum_to_set.inspect}"
57
+ end
58
+ @enum_changed ||= self[enum_column] != old_value
59
+ end
60
+
61
+ define_method("#{enum_name}_has_changed?") do
62
+ !!@enum_changed
63
+ end
64
+
65
+ define_method("#{enum_column}_check_for_valid_type_of_enum") do
66
+ return true if self[enum_column].nil? || self[enum_column].to_s.empty?
67
+ begin
68
+ enum_class.const_get(self[enum_column])
69
+ rescue NameError => e
70
+ self.errors.add(enum_column.to_sym, "Wrong type '#{self[enum_column]}' for enum '#{enum_name}'")
71
+ return false
72
+ end
73
+ return true
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,110 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'active_support'
5
+ require 'active_record'
6
+ module Degu
7
+ module HasSet
8
+ VERSION = '0.0.4'
9
+
10
+ module ClassMethods
11
+ # Use like this:
12
+ #
13
+ # class Person < ActiveRecord::Base
14
+ # has_set :interests
15
+ # end
16
+ def has_set(set_name, options = {})
17
+
18
+ set_column = options.has_key?(:column_name) ? options[:column_name].to_s : "#{set_name}_bitfield"
19
+
20
+ begin
21
+ enum_class = options.has_key?(:enum_class) ? options[:enum_class] : set_name.to_s.camelcase.constantize
22
+ rescue NameError => ne
23
+ raise NameError, "There ist no class to take the set entries from (#{ne.message})."
24
+ end
25
+
26
+ # Extend enum_class with field_name method
27
+ enum_class.class_eval <<-EOF
28
+ def field_name
29
+ '#{set_name.to_s.singularize}_' + self.name.underscore
30
+ end
31
+ EOF
32
+
33
+ define_method("#{set_name}=") do |argument_value|
34
+ self[set_column] =
35
+ unless argument_value.nil?
36
+ set_elements =
37
+ if String === argument_value
38
+ argument_value.split(',').map(&:strip)
39
+ else
40
+ Array(argument_value)
41
+ end.map do |set_element|
42
+ enum_class[set_element]
43
+ end
44
+ set_elements.all? or raise ArgumentError, "element #{argument_value.inspect} contains invalid elements"
45
+ value = 0
46
+ set_elements.each do |set_element|
47
+ mask = 1 << set_element.bitfield_index
48
+ if mask & value == mask
49
+ next
50
+ else
51
+ value |= mask
52
+ end
53
+ end
54
+ value
55
+ end
56
+ end
57
+
58
+ define_method(set_name) do
59
+ value = self[set_column]
60
+ case
61
+ when value.blank?
62
+ ;;
63
+ when value.zero?
64
+ []
65
+ else
66
+ set_elements = enum_class.values.select do |enum_element|
67
+ send("#{set_name.to_s.singularize}_#{enum_element.name.underscore}?")
68
+ end
69
+ # special to_s method for element-array
70
+ class << set_elements
71
+ def to_s
72
+ map(&:name) * ', '
73
+ end
74
+ end
75
+ set_elements
76
+ end
77
+ end
78
+
79
+ # TODO: This should be a class method
80
+ define_method("available_#{set_name}") do
81
+ self.methods.grep(/#{set_name.to_s.singularize}_\w+[^\?=]$/).sort.map(&:to_s)
82
+ end
83
+
84
+ enum_class.values.each do |enum|
85
+ define_method("#{set_name.to_s.singularize}_#{enum.name.underscore}?") do
86
+ mask = 1 << enum.bitfield_index
87
+ self[set_column] & mask == mask
88
+ end
89
+
90
+ alias_method :"#{set_name.to_s.singularize}_#{enum.name.underscore}", :"#{set_name.to_s.singularize}_#{enum.name.underscore}?"
91
+
92
+ define_method("#{set_name.to_s.singularize}_#{enum.name.underscore}=") do |true_or_false|
93
+ mask = 1 << enum.bitfield_index
94
+ current_value = mask & self[set_column] == mask
95
+ true_or_false = true if true_or_false.to_s == "true" || true_or_false.respond_to?(:to_i) && true_or_false.to_i == 1
96
+ true_or_false = false if true_or_false.to_s == "false" || true_or_false.respond_to?(:to_i) && true_or_false.to_i == 0
97
+
98
+ if current_value != true_or_false
99
+ true_or_false ? self[set_column] |= mask : self[set_column] &= ~mask
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def self.included(modul)
107
+ modul.extend(ClassMethods)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,6 @@
1
+ module Degu
2
+ end
3
+ require 'degu/version'
4
+ require 'degu/renum'
5
+ require 'degu/has_set'
6
+ require 'degu/has_enum'
@@ -0,0 +1,226 @@
1
+ require 'forwardable'
2
+ begin
3
+ require 'json'
4
+ rescue LoadError
5
+ end
6
+
7
+ module Degu
8
+ module Renum
9
+
10
+ # This is the superclass of all enumeration classes.
11
+ # An enumeration class is Enumerable over its values and exposes them by numeric index via [].
12
+ # Values are also comparable, sorting into the order in which they're declared.
13
+ class EnumeratedValue
14
+
15
+ class << self
16
+ include Enumerable
17
+ extend Forwardable
18
+
19
+ def_delegators :values, :first, :last, :each
20
+
21
+ # Returns an array of values in the order they're declared.
22
+ def values
23
+ @values ||= []
24
+ end
25
+
26
+ alias all values
27
+
28
+ # This class encapsulates an enum field (аctually a method with arity == 0).
29
+ class Field < Struct.new('Field', :name, :options, :block)
30
+ # Returns true if the :default option was given.
31
+ def default?
32
+ options.key?(:default)
33
+ end
34
+
35
+ # Returns the value of the :default option.
36
+ def default
37
+ options[:default]
38
+ end
39
+
40
+ # Returns true if a block was given.
41
+ def block?
42
+ !!block
43
+ end
44
+
45
+ # Determine the default value for the enum value +obj+ if +options+ is
46
+ # the options hash given to the init method.
47
+ def default_value(obj, options)
48
+ field_value = options[name]
49
+ if field_value.nil?
50
+ if default?
51
+ default_value = default
52
+ elsif block?
53
+ default_value = block[obj]
54
+ end
55
+ else
56
+ field_value
57
+ end
58
+ end
59
+
60
+ # Returns the name as a string.
61
+ def to_s
62
+ name.to_s
63
+ end
64
+
65
+ # Returns a detailed string representation of this field.
66
+ def inspect
67
+ "#<#{self.class}: #{self} #{options.inspect}>"
68
+ end
69
+ end
70
+
71
+ # Returns an array of all fields defined on this enum.
72
+ def fields
73
+ @fields ||= []
74
+ end
75
+
76
+ # Defines a field with the name +name+, the options +options+ and the
77
+ # block +block+. The only valid option at the moment is :default which is
78
+ # the default value the field is initialized with.
79
+ def field(name, options = {}, &block)
80
+ name = name.to_sym
81
+ fields.delete_if { |f| f.name == name }
82
+ fields << field = Field.new(name, options, block)
83
+ instance_eval { attr_reader field.name }
84
+ end
85
+
86
+ # Returns the value with the name +name+ and returns it.
87
+ def with_name name
88
+ values_by_name[name.to_s]
89
+ end
90
+
91
+ # Returns a hash that maps names to their respective values values.
92
+ def values_by_name
93
+ @values_by_name ||= values.inject({}) do |memo, value|
94
+ memo[value.name] = value
95
+ memo
96
+ end.freeze
97
+ end
98
+
99
+ # Returns the enum value for +index+. If +index+ is an Integer the
100
+ # index-th enum value is returned. Otherwise +index+ is converted into a
101
+ # String. For strings that start with a capital letter the with_name
102
+ # method is used to determine the enum value with the name +index+. If
103
+ # the string starts with a lowercase letter it is converted into
104
+ # camelcase first, that is foo_bar will be converted into FooBar, before
105
+ # with_name is called with this new value.
106
+ def [](index)
107
+ case index
108
+ when Integer
109
+ values[index]
110
+ when self
111
+ values[index.index]
112
+ else
113
+ name = index.to_s
114
+ case name
115
+ when /\A(\d+)\Z/
116
+ return values[$1.to_i]
117
+ when /\A[a-z]/
118
+ name = name.gsub(/(?:\A|_)(.)/) { $1.upcase }
119
+ end
120
+ with_name(name)
121
+ end
122
+ end
123
+
124
+ # Returns the enum instance stored in the marshalled string +string+.
125
+ def _load(string)
126
+ with_name Marshal.load(string)
127
+ end
128
+
129
+ if defined?(::JSON)
130
+ # Fetches the correct enum determined by the deserialized JSON
131
+ # document.
132
+ def json_create(data)
133
+ JSON.deep_const_get(data[JSON.create_id])[data['name']]
134
+ end
135
+ end
136
+ end
137
+
138
+ include Comparable
139
+
140
+ # Name of this enumerated value as a string.
141
+ attr_reader :name
142
+
143
+ # Index of this enumerated value as an integer.
144
+ attr_reader :index
145
+
146
+ alias_method :id, :index
147
+
148
+ # Creates an enumerated value named +name+ with a unique autoincrementing
149
+ # index number.
150
+ def initialize name
151
+ @name = name.to_s.freeze
152
+ @index = self.class.values.size
153
+ self.class.values << self
154
+ end
155
+
156
+ # This is the standard init method method which has an arbitrary number of
157
+ # arguments. If the last argument is a Hash and its keys are defined fields
158
+ # their respective values will be used to initialize the fields. If you
159
+ # want to use this method from an enum and define your own custom init
160
+ # method there, don't forget to call super from your method.
161
+ def init(*args)
162
+ if Hash === options = args.last
163
+ for field in self.class.fields
164
+ instance_variable_set "@#{field}", field.default_value(self, options)
165
+ end
166
+ end
167
+ end
168
+
169
+ # Returns the fully qualified name of the constant referring to this value.
170
+ # Don't override this if you're using Renum with the constantize_attribute
171
+ # plugin, which relies on this behavior.
172
+ def to_s
173
+ "#{self.class}::#{name}"
174
+ end
175
+
176
+ # Sorts enumerated values into the order in which they're declared.
177
+ def <=> other
178
+ index <=> other.index
179
+ end
180
+
181
+ # Returns a marshalled string for this enum instance.
182
+ def _dump(limit = -1)
183
+ Marshal.dump(name, limit)
184
+ end
185
+
186
+ if defined?(::JSON)
187
+ # Set the given fields in the +obj+ hash
188
+ def set_fields(obj, fields)
189
+ fields.each do |f|
190
+ name = f.name
191
+ value = instance_variable_get("@#{name}")
192
+ value.nil? and next
193
+ obj[name] = value
194
+ end
195
+ end
196
+
197
+ # Returns an enum (actually more a reference to an enum) serialized as a
198
+ # JSON document.
199
+ def as_json(opts = {}, *a)
200
+ opts ||= {}
201
+ obj = {
202
+ JSON.create_id => self.class.name,
203
+ :name => name,
204
+ }
205
+ case fields_opt = opts[:fields]
206
+ when nil, false
207
+ when true
208
+ set_fields obj, self.class.fields
209
+ when Array
210
+ fields_opt = fields_opt.map(&:to_sym)
211
+ set_fields obj, self.class.fields.select { |field| fields_opt.include?(field.name) }
212
+ else
213
+ raise ArgumentError, "unexpected fields option #{fields_opt.inspect}"
214
+ end
215
+ obj.as_json(opts)
216
+ end
217
+
218
+ def to_json(opts, *a)
219
+ obj = as_json(opts)
220
+ opts.respond_to?(:fields) and opts.delete(:fields)
221
+ obj.to_json(opts, *a)
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end