shellopts 2.0.0.pre.3 → 2.0.0.pre.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,9 +3,9 @@ require 'shellopts/idr.rb'
3
3
 
4
4
  module ShellOpts
5
5
  module Idr
6
- # Generates an Idr::Program from an Ast::Program object
7
- def self.generate(ast, messenger)
8
- Idr::Program.new(ast, messenger)
6
+ # Generates an Idr::Program from a ShellOpts object
7
+ def self.generate(shellopts)
8
+ Idr::Program.new(shellopts)
9
9
  end
10
10
  end
11
11
  end
@@ -18,7 +18,7 @@ module ShellOpts
18
18
  attr_reader :option_list
19
19
 
20
20
  # List of commands in declaration order
21
- attr_reader :command_list
21
+ attr_reader :subcommand_list
22
22
 
23
23
  # Multihash from option key or names (both short and long names) to option. This
24
24
  # means an option can occur more than once as the hash value
@@ -31,9 +31,9 @@ module ShellOpts
31
31
  # Sub-commands of this command. Is a multihash from sub-command key or
32
32
  # name to command object. Lazily constructed because subcommands are added
33
33
  # after initialization
34
- def commands()
35
- @command_multihash ||= @command_list.flat_map { |command|
36
- command.identifiers.map { |name| [name, command] }
34
+ def subcommands()
35
+ @subcommand_multihash ||= @subcommand_list.flat_map { |subcommand|
36
+ subcommand.identifiers.map { |name| [name, subcommand] }
37
37
  }.to_h
38
38
  end
39
39
 
@@ -41,16 +41,15 @@ module ShellOpts
41
41
  # if this is the root object. name is the name of the command (without
42
42
  # the exclamation mark), and option_list a list of Option objects
43
43
  def initialize(parent, name, option_list)
44
- super("#{name}!".to_sym)
45
- @name = name
44
+ super("#{name}!".to_sym, name)
46
45
  parent.attach(self) if parent
47
46
  @option_list = option_list
48
- @command_list = []
47
+ @subcommand_list = []
49
48
  end
50
49
 
51
50
  # Return key for the identifier
52
51
  def identifier2key(ident)
53
- options[ident]&.key || commands[ident]&.key
52
+ options[ident]&.key || subcommands[ident]&.key
54
53
  end
55
54
 
56
55
  # Return list of identifiers for the command
@@ -65,16 +64,16 @@ module ShellOpts
65
64
  yield if block_given?
66
65
  puts "options:"
67
66
  indent { option_list.each { |opt| opt.dump } }
68
- puts "commands: "
69
- indent { command_list.each { |cmd| cmd.dump } }
67
+ puts "subcommands: "
68
+ indent { subcommand_list.each { |cmd| cmd.dump } }
70
69
  }
71
70
  end
72
71
  # :nocov:
73
72
 
74
73
  protected
75
- def attach(command)
76
- command.instance_variable_set(:@parent, self)
77
- @command_list << command
74
+ def attach(subcommand)
75
+ subcommand.instance_variable_set(:@parent, self)
76
+ @subcommand_list << subcommand
78
77
  end
79
78
  end
80
79
  end
@@ -10,14 +10,22 @@ module ShellOpts
10
10
  # Key (Symbol) of node. Unique within the enclosing command
11
11
  attr_reader :key
12
12
 
13
- def initialize(key)
14
- @key = key
13
+ # Name of node. The name of an option is without the prefixed '-' or
14
+ # '--', the name of a command is without the suffixed '!'. Note that name
15
+ # collisions can happen between options and commands names
16
+ attr_reader :name
17
+
18
+ def initialize(key, name)
19
+ @key, @name = key, name
15
20
  end
16
21
 
17
22
  # :nocov:
18
23
  def dump(&block)
19
24
  puts key.inspect
20
- indent { yield } if block_given?
25
+ indent {
26
+ puts "name: #{name.inspect}"
27
+ yield if block_given?
28
+ }
21
29
  end
22
30
  # :nocov:
23
31
  end
@@ -27,7 +27,8 @@ module ShellOpts
27
27
  # informal name of the option argument (eg. 'FILE') or nil if not present
28
28
  def initialize(short_names, long_names, flags, label = nil)
29
29
  @key_name = long_names.first || short_names.first
30
- super(@key_name.sub(/^-+/, "").to_sym)
30
+ name = @key_name.sub(/^-+/, "")
31
+ super(name.to_sym, name)
31
32
  @short_names, @long_names = short_names, long_names
32
33
  @flags = flags.map { |flag| [flag, true] }.to_h
33
34
  @label = label
@@ -17,7 +17,7 @@ module ShellOpts
17
17
  def usage
18
18
  (
19
19
  render_options(option_list) +
20
- command_list.map { |cmd| render_command(cmd) } +
20
+ subcommand_list.map { |cmd| render_subcommand(cmd) } +
21
21
  args
22
22
  ).flatten.join(" ")
23
23
  end
@@ -32,9 +32,9 @@ module ShellOpts
32
32
  # :nocov:
33
33
 
34
34
  private
35
- def render_command(command)
36
- [command.name] + render_options(command.option_list) +
37
- command.command_list.map { |cmd| render_command(cmd) }.flatten
35
+ def render_subcommand(subcommand)
36
+ [subcommand.name] + render_options(subcommand.option_list) +
37
+ subcommand.subcommand_list.map { |cmd| render_subcommand(cmd) }.flatten
38
38
  end
39
39
 
40
40
  def render_options(options)
@@ -13,15 +13,14 @@ module ShellOpts
13
13
  # and a value. Options have their (optional) argument as value while
14
14
  # commands use +self+ as value
15
15
  class Node
16
+ # Parent node. nil for the top-level Program object
17
+ attr_reader :parent
18
+
16
19
  # Unique key (within context) for the option or command. nil for the
17
20
  # top-level Program object
18
- #
19
- # It is usually the first long option if present and else the first short
20
- # option turned into a Symbol by first removing prefixed dashed, eg.
21
- # '--all' becomes :all
22
21
  attr_reader :key
23
22
 
24
- # Name of command and option as used on the command line
23
+ # Name of command or option as used on the command line
25
24
  attr_reader :name
26
25
 
27
26
  # Value of node. This can be a simple value (String, Integer, or Float),
@@ -33,10 +32,13 @@ module ShellOpts
33
32
  # arguments or if an optional argument is missing.
34
33
  attr_reader :value
35
34
 
35
+ # The top-level Program object
36
+ def program() @program ||= (parent&.program || self) end
37
+
36
38
  protected
37
39
  # Copy arguments into instance variables
38
- def initialize(ast, key, name, value)
39
- @ast, @key, @name, @value = ast, key, name, value
40
+ def initialize(parent, ast, key, name, value)
41
+ @parent, @ast, @key, @name, @value = parent, ast, key, name, value
40
42
  end
41
43
 
42
44
  # The AST node for this Idr object
@@ -54,9 +56,9 @@ module ShellOpts
54
56
  protected
55
57
  # Initialize with defauls from the Ast. +value+ is set to true if option
56
58
  # doesn't take an argument
57
- def initialize(ast)
59
+ def initialize(parent, ast)
58
60
  value = ast.grammar.argument? ? ast.value : true
59
- super(ast, ast.key, ast.name, value)
61
+ super(parent, ast, ast.key, ast.name, value)
60
62
  end
61
63
  end
62
64
 
@@ -71,9 +73,9 @@ module ShellOpts
71
73
  alias :values :value
72
74
 
73
75
  # Name is set to the key name and value to an array of option values
74
- def initialize(key, name, options)
76
+ def initialize(parent, key, name, options)
75
77
  @names = options.map(&:name)
76
- super(nil, key, name, options.map(&:value))
78
+ super(parent, nil, key, name, options.map(&:value))
77
79
  end
78
80
  end
79
81
 
@@ -91,13 +93,13 @@ module ShellOpts
91
93
  attr_reader :subcommand
92
94
 
93
95
  # True if ident is declared
94
- def declared?(ident) option?(ident) || command?(ident) end
96
+ def declared?(ident) option?(ident) || subcommand?(ident) end
95
97
 
96
98
  # True if ident is declared as an option
97
99
  def option?(ident) grammar.options.key?(ident) end
98
100
 
99
101
  # True if ident is declared as a command
100
- def command?(ident) grammar.commands.key?(ident) end
102
+ def subcommand?(ident) grammar.subcommands.key?(ident) end
101
103
 
102
104
  # True if ident is present
103
105
  def key?(ident)
@@ -120,8 +122,8 @@ module ShellOpts
120
122
  end
121
123
 
122
124
  # Apply defaults recursively. Values can be lambdas that will be evaluated to
123
- # get the default value
124
- def apply(defaults = {}) end
125
+ # get the default value. TODO
126
+ def apply(defaults = {}) raise InternalError, "Not implemented" end
125
127
 
126
128
  # Return options and command as an array
127
129
  def to_a() @ast.values end
@@ -129,49 +131,52 @@ module ShellOpts
129
131
  # Return options and command as a hash. The hash also define the
130
132
  # singleton method #subcommand that returns the key of the subcommand
131
133
  #
132
- # +key+ controls the type of keys used: +:key+ (the default) use the
133
- # symbolic key, +:name+ use key_name. Note that using +:name+ can cause name collisions between
134
- # option and command names and that #to_s raises an exception if it detects a collision
134
+ # +key_type+ controls the type of keys used: +:key+ (the default) use the
135
+ # symbolic key, +:name+ use #name. Note that using +:name+ can cause
136
+ # name collisions between option and command names
135
137
  #
136
138
  # +aliases+ maps from key to replacement key (which could be any object).
137
139
  # +aliases+ can be used to avoid name collisions between options and
138
- # commands
140
+ # commands when using key_format: :name
139
141
  #
140
- # IDEA: Make subcommand _not_ follow the +key+ setting so that setting key to
141
- # IDEA: Add a singleton method #subcommand to the hash
142
+ # IDEA: Add a singleton methods to the hash with #name, #usage, etc.
142
143
  #
143
- def to_h(use: :key, aliases: {})
144
+ def to_h(key_type: ::ShellOpts.default_key_type, aliases: {})
145
+ keys = map_keys(key_type, aliases)
144
146
  value = {}
145
147
  value.define_singleton_method(:subcommand) { nil }
146
- options.values.each { |opt|
147
- ident = aliases[opt.key] || (use == :key ? opt.key : opt.ast.grammar.key_name)
148
- !value.key?(ident) or raise ConversionError, "Duplicate key: #{ident.inspect}"
148
+ options.values.each { |opt| # includes subcommand
149
+ key = keys[opt.key]
149
150
  case opt
150
151
  when Option
151
- value[ident] = opt.value
152
+ value[key] = opt.value
152
153
  when Command
153
- value[ident] = opt.value.to_h
154
- value.define_singleton_method(:subcommand) { ident } # Redefine
154
+ value[key] = opt.value.to_h(key_type: key_type, aliases: aliases[opt.key] || {})
155
+ value.define_singleton_method(:subcommand) { key } # Redefine
155
156
  else
157
+ # :nocov:
156
158
  raise InternalError, "Oops"
159
+ # :nocov:
157
160
  end
158
161
  }
159
162
  value
160
163
  end
161
164
 
162
165
  # Return options and command as a struct
163
- def to_struct(key = :key, aliases = {}) OptionStruct.new(self, key, aliases) end
166
+ def to_struct(key_type: ::ShellOpts.default_key_type, aliases: {})
167
+ OptionStruct.new(self, key_type, aliases)
168
+ end
164
169
 
165
170
  protected
166
171
  # Initialize an Idr::Command object and all dependent objects
167
- def initialize(ast)
168
- super(ast, ast.key, ast.name, self)
169
- @option_list = ast.options.map { |node| SimpleOption.new(node) }
170
- @subcommand = Command.new(ast.command) if ast.command
172
+ def initialize(parent, ast)
173
+ super(parent, ast, ast.key, ast.name, self)
174
+ @option_list = ast.options.map { |node| SimpleOption.new(self, node) }
175
+ @subcommand = Command.new(self, ast.subcommand) if ast.subcommand
171
176
  @options = @option_list.group_by { |option| option.key }.map { |key, option_list|
172
177
  option =
173
178
  if ast.grammar.options[key].repeated?
174
- OptionGroup.new(key, ast.grammar.options[key].key_name, option_list)
179
+ OptionGroup.new(self, key, ast.grammar.options[key].key_name, option_list)
175
180
  else
176
181
  option_list.first
177
182
  end
@@ -179,30 +184,52 @@ module ShellOpts
179
184
  }.to_h
180
185
  @options[subcommand.key] = @subcommand if @subcommand
181
186
  end
187
+
188
+ # Internal-key to used-key map. Checks for reserved words and
189
+ # name-collisions
190
+ def map_keys(key_type, aliases, reserved_words = [])
191
+ keys = {}
192
+ used_keys = {}
193
+ (grammar.option_list + grammar.subcommand_list).each { |node|
194
+ internal_key = node.key
195
+ key = aliases[internal_key] || (key_type == :name ? node.name.to_sym : internal_key)
196
+ !reserved_words.include?(key) or
197
+ raise ::ShellOpts::ConversionError, "'#{key}' is a reserved word"
198
+ !used_keys.key?(key) or
199
+ raise ::ShellOpts::ConversionError, "Name collision between '--#{key}' and '#{key}!'"
200
+ keys[internal_key] = key
201
+ used_keys[key] = true
202
+ }
203
+ keys
204
+ end
182
205
  end
183
206
 
184
207
  class Program < Command
208
+ # Name of program
209
+ def name() @shellopts.name end
210
+ def name=(name) @shellopts.name = name end
211
+
212
+ # Usage string
213
+ def usage() @shellopts.usage end
214
+ def usage=(usage) @shellopts.usage = usage end
215
+
185
216
  # #key is nil for the top-level Program object
186
217
  def key() nil end
187
218
 
188
219
  # Remaining command line arguments
189
- def args() @ast.arguments end
190
-
191
- # Messenger object that is used to emit error messages. It should
192
- # implement #error(*args) and #fail(*args)
193
- attr_reader :messenger
220
+ def args() @shellopts.args end
194
221
 
195
222
  # Initialize the top-level Idr::Program object
196
- def initialize(ast, messenger)
197
- @messenger = messenger
198
- super(ast)
223
+ def initialize(shellopts)
224
+ @shellopts = shellopts
225
+ super(nil, shellopts.ast)
199
226
  end
200
227
 
201
228
  # Emit error message and a usage description before exiting with status 1
202
- def error(*args) messenger.error(*error_messages) end
229
+ def error(*args) @shellopts.error(*error_messages) end
203
230
 
204
231
  # Emit error message before exiting with status 1
205
- def fail(*args) messenger.fail(*error_messages) end
232
+ def fail(*args) @shellopts.fail(*error_messages) end
206
233
  end
207
234
  end
208
235
  end
@@ -0,0 +1,10 @@
1
+
2
+ module ShellOpts
3
+ # Gives access to the ruby main object
4
+ module Main
5
+ CALLER_RE = /^.*:in `<main>'$/
6
+ def self.main() TOPLEVEL_BINDING.eval("self") end
7
+ end
8
+ end
9
+
10
+
@@ -3,88 +3,8 @@ require 'shellopts/shellopts.rb'
3
3
  require 'shellopts/idr'
4
4
 
5
5
  module ShellOpts
6
- class OptionStruct < BasicObject
7
- # +key=:name+ cause command methods to be named without the exclamation
8
- # mark. It doesn't change how options are named
9
- def self.new(idr, key = :key, aliases = {})
10
- ast = idr.instance_variable_get("@ast")
11
- grammar = ast.grammar
12
- instance = allocate
13
-
14
- # Generate option accessor methods
15
- grammar.option_list.each { |option|
16
- key = alias_key(option.key, aliases)
17
- instance.instance_eval("def #{key}() @#{key} end")
18
- present = set_variable(instance, "@#{key}", idr[option.key])
19
- instance.instance_eval("def #{key}?() #{present} end")
20
- }
21
-
22
- # Generate #subcommand default methods
23
- if !idr.subcommand
24
- instance.instance_eval("def subcommand() nil end")
25
- instance.instance_eval("def subcommand?() false end")
26
- instance.instance_eval("def subcommand!() nil end")
27
- end
28
-
29
- # Generate subcommand methods
30
- grammar.command_list.each { |command|
31
- key = alias_key(command.key, aliases)
32
- if command.key == idr.subcommand&.key
33
- struct = OptionStruct.new(idr.subcommand, aliases[idr.subcommand.key] || {})
34
- set_variable(instance, "@subcommand", struct)
35
- instance.instance_eval("def #{key}() @subcommand end")
36
- instance.instance_eval("def subcommand() :#{key} end")
37
- instance.instance_eval("def subcommand?() true end")
38
- instance.instance_eval("def subcommand!() @subcommand end")
39
- else
40
- instance.instance_eval("def #{key}() nil end")
41
- end
42
- }
43
-
44
- instance
45
- end
46
-
47
- private
48
- # Return class of object. #class is not defined for BasicObjects so this
49
- # method provides an alternative way of getting the class
50
- def self.class_of(object)
51
- # https://stackoverflow.com/a/18621313/2130986
52
- ::Kernel.instance_method(:class).bind(object).call
53
- end
54
-
55
- # Replace key with alias and check against the list of reserved words
56
- def self.alias_key(internal_key, aliases)
57
- key = aliases[internal_key] || internal_key
58
- !RESERVED_WORDS.include?(key.to_s) or
59
- raise ::ShellOpts::ConversionError, "Can't create struct: '#{key}' is a reserved word"
60
- key
61
- end
62
-
63
- # Shorthand helper method. Substitutes the undefined ObjectStruct#instance_variable_set
64
- def self.set_variable(this, var, value)
65
- # https://stackoverflow.com/a/18621313/2130986
66
- ::Kernel.instance_method(:instance_variable_set).bind(this).call(var, value)
67
- end
68
-
69
- BASIC_OBJECT_RESERVED_WORDS = %w(
70
- __id__ __send__ instance_eval instance_exec method_missing
71
- singleton_method_added singleton_method_removed
72
- singleton_method_undefined)
73
- OPTIONS_STRUCT_RESERVED_WORDS = %w(subcommand)
74
- RESERVED_WORDS = BASIC_OBJECT_RESERVED_WORDS + OPTIONS_STRUCT_RESERVED_WORDS
75
- end
76
- end
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
- __END__
86
-
87
- module ShellOpts
6
+ # FIXME: Outdated
7
+ #
88
8
  # Struct representation of options. Usually created by ShellOpts::to_struct
89
9
  #
90
10
  # OptionStruct objects give easy access to configuration option values but
@@ -136,110 +56,93 @@ module ShellOpts
136
56
  # reserved words or with the special #command method
137
57
  #
138
58
  class OptionStruct < BasicObject
139
- # Create a new OptionStruct instance from an AST. The optional
140
- # +options_hash+ argument is used to create subcommands without creating a
141
- # new options_hash argument. It is not meant for end-users. The
142
- # +command_alias+ names the method holding the key for the subcommand (if
143
- # any)
144
- def self.new(ast, options_hash = OptionsHash.new(ast), command_alias: :command)
59
+ # Create a OptionStruct object recursively from an Idr::Command object
60
+ def self.new(idr, key_type, aliases = {})
61
+ # Shorthands
62
+ ast = idr.instance_variable_get("@ast")
63
+ grammar = ast.grammar
64
+
65
+ # Get key map
66
+ keys = idr.send(:map_keys, key_type, aliases, RESERVED_WORDS)
67
+
68
+ # Allocate OptionStruct instance
145
69
  instance = allocate
146
- set_variable(instance, "@__options_hash__", options_hash)
147
70
 
148
- # Check for reserved words and +command_alias+
149
- options_hash.keys.each { |key|
150
- !RESERVED_WORDS.include?(key.to_s) or
151
- raise ::ShellOpts::ConversionError, "Can't create struct: '#{key}' is a reserved word"
152
- key != command_alias or
153
- raise ::ShellOpts::ConversionError, "Can't create struct: '#{key}' is the command alias"
154
- }
71
+ # Set reference to Idr object. Is currently unused
72
+ set_variable(instance, "@__idr__", idr)
155
73
 
156
- # Create accessor methods
157
- ast.grammar.option_list.each { |option|
158
- instance.instance_eval("def #{option.key}() @#{option.key} end")
159
- instance.instance_eval("def #{option.key}?() false end")
74
+ # Generate general option accessor methods
75
+ grammar.option_list.each { |option|
76
+ key = keys[option.key]
77
+ instance.instance_eval("def #{key}() @#{key} end")
78
+ instance.instance_eval("def #{key}?() false end")
160
79
  }
161
- ast.grammar.command_list.each { |command|
162
- instance.instance_eval("def #{command.key}() nil end")
80
+
81
+ # Generate accessor method for present options
82
+ idr.option_list.each { |option|
83
+ key = keys[option.key]
84
+ set_variable(instance, "@#{key}", idr[option.key])
85
+ instance.instance_eval("def #{key}?() true end")
163
86
  }
164
87
 
165
- # Assign values
166
- options_hash.each { |key, value|
167
- if value.is_a?(OptionsHash)
168
- set_variable(instance, "@__command__", OptionStruct.new(value.ast, value))
169
- instance.instance_eval("def #{key}() @__command__ end")
88
+ # Generate general #subcommand methods
89
+ if !idr.subcommand
90
+ instance.instance_eval("def subcommand() nil end")
91
+ instance.instance_eval("def subcommand?() false end")
92
+ instance.instance_eval %(
93
+ def subcommand!(*msgs)
94
+ $stderr.puts "in subcommand!"
95
+ ::Kernel.raise ::ShellOpts::UserError, (msgs.empty? ? 'No command' : msgs.join)
96
+ end
97
+ )
98
+ end
99
+
100
+ # Generate individual subcommand methods
101
+ grammar.subcommand_list.each { |subcommand|
102
+ key = keys[subcommand.key]
103
+ if subcommand.key == idr.subcommand&.key
104
+ struct = OptionStruct.new(idr.subcommand, key_type, aliases[idr.subcommand.key] || {})
105
+ set_variable(instance, "@subcommand", struct)
106
+ instance.instance_eval("def #{key}() @subcommand end")
107
+ instance.instance_eval("def subcommand() :#{key} end")
108
+ instance.instance_eval("def subcommand?() true end")
109
+ instance.instance_eval("def subcommand!(*msgs) :#{key} end")
170
110
  else
171
- set_variable(instance, "@#{key}", value)
172
- instance.instance_eval("def #{key}?() true end")
111
+ instance.instance_eval("def #{key}() nil end")
173
112
  end
174
113
  }
175
114
 
176
- # Command accessor method
177
- instance.instance_eval("def #{command_alias}() @__options_hash__.command end")
178
-
179
115
  instance
180
116
  end
181
117
 
182
- # Return the OptionsHash object from the instance
183
- def self.options_hash(instance)
184
- get_variable(instance, "@__options_hash__")
185
- end
186
-
118
+ private
187
119
  # Return class of object. #class is not defined for BasicObjects so this
188
- # method provides an alternative way of getting the class a BasicObject
120
+ # method provides an alternative way of getting the class
189
121
  def self.class_of(object)
190
122
  # https://stackoverflow.com/a/18621313/2130986
191
123
  ::Kernel.instance_method(:class).bind(object).call
192
124
  end
193
125
 
194
- # Return the number of options and commands
195
- def self.size(instance)
196
- options_hash(instance).size
197
- end
198
-
199
- # Return the option and command keys. The keys are in order of occurrence
200
- # on the command line. A subcommand will always be the last element
201
- def self.keys(instance)
202
- options_hash(instance).keys
203
- end
204
-
205
- # Return the actual option name used on the command line for +name+. Use
206
- # +index+ to select between repeated options. Return the name of the
207
- # program/subcommand if key is nil
208
- def self.name(struct, key = nil, index = nil)
209
- options_hash(struct).name(key, index)
210
- end
211
-
212
- # Return the AST node for the option key or the AST node for the
213
- # OptionStruct if key is nil. Use +index+ to select between repeated
214
- # options. Raise InternalError if key doesn't exists
215
- def self.node(struct, key = nil, index = nil)
216
- options_hash(struct).node(key, index)
217
- end
218
-
219
- # Return key of the command of the struct (possibly nil)
220
- def self.command(struct)
221
- options_hash(struct).command
222
- end
223
-
224
- private
225
- BASIC_OBJECT_RESERVED_WORDS = %w(
226
- __id__ __send__ instance_eval instance_exec method_missing
227
- singleton_method_added singleton_method_removed
228
- singleton_method_undefined)
229
- OPTIONS_STRUCT_RESERVED_WORDS = %w(__options_hash__ __command__)
230
- RESERVED_WORDS = BASIC_OBJECT_RESERVED_WORDS + OPTIONS_STRUCT_RESERVED_WORDS
231
-
232
- # Shorthand helper method. Substitutes the undefined ObjectStruct#instance_variable_set
126
+ # Class method implementation of ObjectStruct#instance_variable_set that is
127
+ # not defined in a BasicObject
233
128
  def self.set_variable(this, var, value)
234
129
  # https://stackoverflow.com/a/18621313/2130986
235
130
  ::Kernel.instance_method(:instance_variable_set).bind(this).call(var, value)
236
131
  end
237
132
 
238
- # Shorthand helper method: Substitutes the undefined ObjectStruct#instance_variable_get
133
+ # Class method implementation of ObjectStruct#instance_variable_get that is
134
+ # not defined in a BasicObject
239
135
  def self.get_variable(this, var)
240
136
  # https://stackoverflow.com/a/18621313/2130986
241
137
  ::Kernel.instance_method(:instance_variable_get).bind(this).call(var)
242
138
  end
139
+
140
+ BASIC_OBJECT_RESERVED_WORDS = %w(
141
+ __id__ __send__ instance_eval instance_exec method_missing
142
+ singleton_method_added singleton_method_removed
143
+ singleton_method_undefined).map(&:to_sym)
144
+ OPTIONS_STRUCT_RESERVED_WORDS = %w(__idr__ subcommand).map(&:to_sym)
145
+ RESERVED_WORDS = BASIC_OBJECT_RESERVED_WORDS + OPTIONS_STRUCT_RESERVED_WORDS
243
146
  end
244
- end
147
+ end
245
148