Class: ElasticGraph::SchemaDefinition::SchemaElements::EnumType

Inherits:
Struct
  • Object
show all
Includes:
Mixins::CanBeGraphQLOnly, Mixins::HasDerivedGraphQLTypeCustomizations, Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::VerifiesGraphQLName
Defined in:
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb

Overview

Defines a GraphQL enum type. The type is restricted to an enumerated set of values, each with a unique name. Use value or values to define the enum values in the passed block.

Note: if required by your configuration, this may generate a pair of Enum types (an input enum and an output enum).

Examples:

Define an enum type

ElasticGraph.define_schema do |schema|
  schema.enum_type "Currency" do |t|
    # in the block, `t` is an EnumType
    t.value "USD"
  end
end

Instance Attribute Summary collapse

Attributes included from Mixins::HasDocumentation

#doc_comment

Instance Method Summary collapse

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

#customize_derived_type_fields, #customize_derived_types

Methods included from Mixins::HasDirectives

#directive, #directives, #directives_sdl

Methods included from Mixins::HasDocumentation

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

Methods included from Mixins::CanBeGraphQLOnly

#graphql_only, #graphql_only?

Methods included from Mixins::VerifiesGraphQLName

verify_name!

Instance Attribute Details

#for_outputBoolean

Returns true if this enum is used for both input and output; false if it is for input only.

Returns:

  • (Boolean)

    true if this enum is used for both input and output; false if it is for input only



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 39

class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
  # @dynamic type_ref, graphql_only?
  prepend Mixins::VerifiesGraphQLName
  include Mixins::CanBeGraphQLOnly
  include Mixins::HasDocumentation
  include Mixins::HasDirectives
  include Mixins::HasDerivedGraphQLTypeCustomizations
  include Mixins::HasReadableToSAndInspect.new { |e| e.name }

  # @private
  def initialize(schema_def_state, name)
    # @type var values_by_name: ::Hash[::String, EnumValue]
    values_by_name = {}
    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)

    # :nocov: -- currently all invocations have a block
    yield self if block_given?
    # :nocov:
  end

  # @return [String] name of the enum type
  def name
    type_ref.name
  end

  # @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
  def aggregated_values_type
    schema_def_state.type_ref("NonNumeric").as_aggregated_values
  end

  # Defines an enum value for the current enum type.
  #
  # @param value_name [String] name of the enum value
  # @yield [EnumValue] enum value so it can be further customized
  # @return [void]
  #
  # @example Define an enum type with multiple enum values
  #   ElasticGraph.define_schema do |schema|
  #     schema.enum_type "Currency" do |t|
  #       t.value "USD" do |v|
  #         v.documentation "US Dollars."
  #       end
  #
  #       t.value "JPY" do |v|
  #         v.documentation "Japanese Yen."
  #       end
  #     end
  #   end
  def value(value_name, &block)
    alternate_original_name = value_name
    value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)

    if values_by_name.key?(value_name)
      raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
    end

    if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
      raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
    end

    values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
  end

  # Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
  # further via a block.
  #
  # @param value_names [Array<String>] names of the enum values
  # @return [void]
  #
  # @example Define an enum type with multiple enum values
  #   ElasticGraph.define_schema do |schema|
  #     schema.enum_type "Currency" do |t|
  #       t.values "USD", "JPY", "CAD", "GBP"
  #     end
  #   end
  def values(*value_names)
    value_names.flatten.each { |name| value(name) }
  end

  # @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
  def 
     = values_by_name
      .transform_values(&:runtime_metadata)
      .compact

    SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
  end

  # @return [String] GraphQL SDL form of the enum type
  def to_sdl
    if values_by_name.empty?
      raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
    end

    <<~EOS
      #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
        #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
      }
    EOS
  end

  # @private
  def derived_graphql_types
    # Derived GraphQL types must be generated for an output enum. For an enum type that is only
    # used as an input, we do not need derived types.
    return [] unless for_output

    derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
      t.mapping type: "keyword"
      t.json_schema type: "string"
      t.graphql_only graphql_only?
    end.derived_graphql_types

    if (input_enum = as_input).equal?(self)
      derived_scalar_types
    else
      [input_enum] + derived_scalar_types
    end
  end

  # @return [Indexing::FieldType::Enum] indexing representation of this enum type
  def to_indexing_field_type
    Indexing::FieldType::Enum.new(values_by_name.keys)
  end

  # @return [false] enum types are never directly indexed
  def indexed?
    false
  end

  # @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
  def as_input
    input_name = type_ref
      .as_input_enum # To apply the configured format for input enums.
      .to_final_form # To handle a type name override of the input enum.
      .name

    return self if input_name == name

    schema_def_state.factory.new_enum_type(input_name) do |t|
      t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
      t.graphql_only true # input enums are always GraphQL-only.
      t.documentation doc_comment
      directives.each { |dir| dir.duplicate_on(t) }
      values_by_name.each { |_, val| val.duplicate_on(t) }
    end
  end
end

#schema_def_stateState (readonly)

Returns state of the schema.

Returns:

  • (State)

    state of the schema



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 39

class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
  # @dynamic type_ref, graphql_only?
  prepend Mixins::VerifiesGraphQLName
  include Mixins::CanBeGraphQLOnly
  include Mixins::HasDocumentation
  include Mixins::HasDirectives
  include Mixins::HasDerivedGraphQLTypeCustomizations
  include Mixins::HasReadableToSAndInspect.new { |e| e.name }

  # @private
  def initialize(schema_def_state, name)
    # @type var values_by_name: ::Hash[::String, EnumValue]
    values_by_name = {}
    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)

    # :nocov: -- currently all invocations have a block
    yield self if block_given?
    # :nocov:
  end

  # @return [String] name of the enum type
  def name
    type_ref.name
  end

  # @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
  def aggregated_values_type
    schema_def_state.type_ref("NonNumeric").as_aggregated_values
  end

  # Defines an enum value for the current enum type.
  #
  # @param value_name [String] name of the enum value
  # @yield [EnumValue] enum value so it can be further customized
  # @return [void]
  #
  # @example Define an enum type with multiple enum values
  #   ElasticGraph.define_schema do |schema|
  #     schema.enum_type "Currency" do |t|
  #       t.value "USD" do |v|
  #         v.documentation "US Dollars."
  #       end
  #
  #       t.value "JPY" do |v|
  #         v.documentation "Japanese Yen."
  #       end
  #     end
  #   end
  def value(value_name, &block)
    alternate_original_name = value_name
    value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)

    if values_by_name.key?(value_name)
      raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
    end

    if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
      raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
    end

    values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
  end

  # Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
  # further via a block.
  #
  # @param value_names [Array<String>] names of the enum values
  # @return [void]
  #
  # @example Define an enum type with multiple enum values
  #   ElasticGraph.define_schema do |schema|
  #     schema.enum_type "Currency" do |t|
  #       t.values "USD", "JPY", "CAD", "GBP"
  #     end
  #   end
  def values(*value_names)
    value_names.flatten.each { |name| value(name) }
  end

  # @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
  def 
     = values_by_name
      .transform_values(&:runtime_metadata)
      .compact

    SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
  end

  # @return [String] GraphQL SDL form of the enum type
  def to_sdl
    if values_by_name.empty?
      raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
    end

    <<~EOS
      #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
        #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
      }
    EOS
  end

  # @private
  def derived_graphql_types
    # Derived GraphQL types must be generated for an output enum. For an enum type that is only
    # used as an input, we do not need derived types.
    return [] unless for_output

    derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
      t.mapping type: "keyword"
      t.json_schema type: "string"
      t.graphql_only graphql_only?
    end.derived_graphql_types

    if (input_enum = as_input).equal?(self)
      derived_scalar_types
    else
      [input_enum] + derived_scalar_types
    end
  end

  # @return [Indexing::FieldType::Enum] indexing representation of this enum type
  def to_indexing_field_type
    Indexing::FieldType::Enum.new(values_by_name.keys)
  end

  # @return [false] enum types are never directly indexed
  def indexed?
    false
  end

  # @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
  def as_input
    input_name = type_ref
      .as_input_enum # To apply the configured format for input enums.
      .to_final_form # To handle a type name override of the input enum.
      .name

    return self if input_name == name

    schema_def_state.factory.new_enum_type(input_name) do |t|
      t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
      t.graphql_only true # input enums are always GraphQL-only.
      t.documentation doc_comment
      directives.each { |dir| dir.duplicate_on(t) }
      values_by_name.each { |_, val| val.duplicate_on(t) }
    end
  end
end

#values_by_nameHash<String, EnumValue> (readonly)

Returns map of enum values, keyed by name.

Returns:

  • (Hash<String, EnumValue>)

    map of enum values, keyed by name



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 39

class EnumType < Struct.new(:schema_def_state, :type_ref, :for_output, :values_by_name)
  # @dynamic type_ref, graphql_only?
  prepend Mixins::VerifiesGraphQLName
  include Mixins::CanBeGraphQLOnly
  include Mixins::HasDocumentation
  include Mixins::HasDirectives
  include Mixins::HasDerivedGraphQLTypeCustomizations
  include Mixins::HasReadableToSAndInspect.new { |e| e.name }

  # @private
  def initialize(schema_def_state, name)
    # @type var values_by_name: ::Hash[::String, EnumValue]
    values_by_name = {}
    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, true, values_by_name)

    # :nocov: -- currently all invocations have a block
    yield self if block_given?
    # :nocov:
  end

  # @return [String] name of the enum type
  def name
    type_ref.name
  end

  # @return [TypeReference] reference to `AggregatedValues` type to use for this enum.
  def aggregated_values_type
    schema_def_state.type_ref("NonNumeric").as_aggregated_values
  end

  # Defines an enum value for the current enum type.
  #
  # @param value_name [String] name of the enum value
  # @yield [EnumValue] enum value so it can be further customized
  # @return [void]
  #
  # @example Define an enum type with multiple enum values
  #   ElasticGraph.define_schema do |schema|
  #     schema.enum_type "Currency" do |t|
  #       t.value "USD" do |v|
  #         v.documentation "US Dollars."
  #       end
  #
  #       t.value "JPY" do |v|
  #         v.documentation "Japanese Yen."
  #       end
  #     end
  #   end
  def value(value_name, &block)
    alternate_original_name = value_name
    value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)

    if values_by_name.key?(value_name)
      raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
    end

    if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
      raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
    end

    values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
  end

  # Defines multiple enum values. In contrast to {#value}, the enum values cannot be customized
  # further via a block.
  #
  # @param value_names [Array<String>] names of the enum values
  # @return [void]
  #
  # @example Define an enum type with multiple enum values
  #   ElasticGraph.define_schema do |schema|
  #     schema.enum_type "Currency" do |t|
  #       t.values "USD", "JPY", "CAD", "GBP"
  #     end
  #   end
  def values(*value_names)
    value_names.flatten.each { |name| value(name) }
  end

  # @return [SchemaArtifacts::RuntimeMetadata::Enum::Type] runtime metadata for this enum type
  def 
     = values_by_name
      .transform_values(&:runtime_metadata)
      .compact

    SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
  end

  # @return [String] GraphQL SDL form of the enum type
  def to_sdl
    if values_by_name.empty?
      raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
    end

    <<~EOS
      #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
        #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
      }
    EOS
  end

  # @private
  def derived_graphql_types
    # Derived GraphQL types must be generated for an output enum. For an enum type that is only
    # used as an input, we do not need derived types.
    return [] unless for_output

    derived_scalar_types = schema_def_state.factory.new_scalar_type(name) do |t|
      t.mapping type: "keyword"
      t.json_schema type: "string"
      t.graphql_only graphql_only?
    end.derived_graphql_types

    if (input_enum = as_input).equal?(self)
      derived_scalar_types
    else
      [input_enum] + derived_scalar_types
    end
  end

  # @return [Indexing::FieldType::Enum] indexing representation of this enum type
  def to_indexing_field_type
    Indexing::FieldType::Enum.new(values_by_name.keys)
  end

  # @return [false] enum types are never directly indexed
  def indexed?
    false
  end

  # @return [EnumType] converts the enum type to its input form for when different naming is used for input vs output enums.
  def as_input
    input_name = type_ref
      .as_input_enum # To apply the configured format for input enums.
      .to_final_form # To handle a type name override of the input enum.
      .name

    return self if input_name == name

    schema_def_state.factory.new_enum_type(input_name) do |t|
      t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
      t.graphql_only true # input enums are always GraphQL-only.
      t.documentation doc_comment
      directives.each { |dir| dir.duplicate_on(t) }
      values_by_name.each { |_, val| val.duplicate_on(t) }
    end
  end
end

Instance Method Details

#aggregated_values_typeTypeReference

Returns reference to AggregatedValues type to use for this enum.

Returns:

  • (TypeReference)

    reference to AggregatedValues type to use for this enum.



65
66
67
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 65

def aggregated_values_type
  schema_def_state.type_ref("NonNumeric").as_aggregated_values
end

#as_inputEnumType

Returns converts the enum type to its input form for when different naming is used for input vs output enums.

Returns:

  • (EnumType)

    converts the enum type to its input form for when different naming is used for input vs output enums.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 170

def as_input
  input_name = type_ref
    .as_input_enum # To apply the configured format for input enums.
    .to_final_form # To handle a type name override of the input enum.
    .name

  return self if input_name == name

  schema_def_state.factory.new_enum_type(input_name) do |t|
    t.for_output = false # flag that it's not used as an output enum, and therefore `derived_graphql_types` will be empty on it.
    t.graphql_only true # input enums are always GraphQL-only.
    t.documentation doc_comment
    directives.each { |dir| dir.duplicate_on(t) }
    values_by_name.each { |_, val| val.duplicate_on(t) }
  end
end

#indexed?false

Returns enum types are never directly indexed.

Returns:

  • (false)

    enum types are never directly indexed



165
166
167
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 165

def indexed?
  false
end

#nameString

Returns name of the enum type.

Returns:

  • (String)

    name of the enum type



60
61
62
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 60

def name
  type_ref.name
end

#runtime_metadataSchemaArtifacts::RuntimeMetadata::Enum::Type

Returns runtime metadata for this enum type.

Returns:

  • (SchemaArtifacts::RuntimeMetadata::Enum::Type)

    runtime metadata for this enum type



119
120
121
122
123
124
125
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 119

def 
   = values_by_name
    .transform_values(&:runtime_metadata)
    .compact

  SchemaArtifacts::RuntimeMetadata::Enum::Type.new(values_by_name: )
end

#to_indexing_field_typeIndexing::FieldType::Enum

Returns indexing representation of this enum type.

Returns:



160
161
162
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 160

def to_indexing_field_type
  Indexing::FieldType::Enum.new(values_by_name.keys)
end

#to_sdlString

Returns GraphQL SDL form of the enum type.

Returns:

  • (String)

    GraphQL SDL form of the enum type



128
129
130
131
132
133
134
135
136
137
138
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 128

def to_sdl
  if values_by_name.empty?
    raise Errors::SchemaError, "Enum type #{name} has no values, but enums must have at least one value."
  end

  <<~EOS
    #{formatted_documentation}enum #{name} #{directives_sdl(suffix_with: " ")}{
      #{values_by_name.values.map(&:to_sdl).flat_map { |s| s.split("\n") }.join("\n  ")}
    }
  EOS
end

#value(value_name) {|EnumValue| ... } ⇒ void

This method returns an undefined value.

Defines an enum value for the current enum type.

Examples:

Define an enum type with multiple enum values

ElasticGraph.define_schema do |schema|
  schema.enum_type "Currency" do |t|
    t.value "USD" do |v|
      v.documentation "US Dollars."
    end

    t.value "JPY" do |v|
      v.documentation "Japanese Yen."
    end
  end
end

Parameters:

  • value_name (String)

    name of the enum value

Yields:

  • (EnumValue)

    enum value so it can be further customized



87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 87

def value(value_name, &block)
  alternate_original_name = value_name
  value_name = schema_def_state.enum_value_namer.name_for(name, value_name.to_s)

  if values_by_name.key?(value_name)
    raise Errors::SchemaError, "Duplicate value on Enum::Type #{name}: #{value_name}"
  end

  if value_name.length > DEFAULT_MAX_KEYWORD_LENGTH
    raise Errors::SchemaError, "Enum value `#{name}.#{value_name}` is too long: it is #{value_name.length} characters but cannot exceed #{DEFAULT_MAX_KEYWORD_LENGTH} characters."
  end

  values_by_name[value_name] = schema_def_state.factory.new_enum_value(value_name, alternate_original_name, &block)
end

#values(*value_names) ⇒ void

This method returns an undefined value.

Defines multiple enum values. In contrast to #value, the enum values cannot be customized further via a block.

Examples:

Define an enum type with multiple enum values

ElasticGraph.define_schema do |schema|
  schema.enum_type "Currency" do |t|
    t.values "USD", "JPY", "CAD", "GBP"
  end
end

Parameters:

  • value_names (Array<String>)

    names of the enum values



114
115
116
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb', line 114

def values(*value_names)
  value_names.flatten.each { |name| value(name) }
end