wrap_in_module 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,2 +1,25 @@
1
- Usable under the Ruby license. Copyright (C)2004 Joel VanderWerf. Questions to
1
+ This project is licensed under the MIT license which can be seen below.
2
+
3
+ This project was based script.rb which is usable under the Ruby license.
4
+ Copyright (C)2004 Joel VanderWerf. Questions to
2
5
  mailto:vjoel@users.sourceforge.net.
6
+
7
+ Copyright (c) 2012 ReachLocal, Inc.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
10
+ this software and associated documentation files (the "Software"), to deal in
11
+ the Software without restriction, including without limitation the rights to
12
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13
+ of the Software, and to permit persons to whom the Software is furnished to do
14
+ so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
data/README.md CHANGED
@@ -2,23 +2,10 @@
2
2
 
3
3
  This is a Ruby gem I created to house the functionality to be able to wrap
4
4
  various things inside modules. The primary focus of it was to be able to load a
5
- ruby file in using a module as namespace for all the top level Constants,
5
+ Ruby file in using a module as namespace for all the top level Constants,
6
6
  Methods, Classes, Modules, etc. This does the same for any sub ruby scripts
7
7
  that are required as well.
8
8
 
9
- I found this functionality in a ruby script, supprisingly called script.rb
10
- written by Joel VanderWerf released under the Ruby license in 2004. I have
11
- simply wrapped his script inside a gem so that this functionality can be easily
12
- accessed. The following is the description provided with Joel's script with my
13
- gem namespacing.
14
-
15
- `WrapInModule::Script` is a subclass of Module. A module which is an instance
16
- of the `WrapInModule::Script` class encapsulates in its scope the top-level
17
- methods, top-level constants, and instance variables defined in a ruby script
18
- file (and its dependent files) loaded by a ruby program. This allows use of
19
- script files to define objects that can be loaded into a program in much the
20
- same way that objects can be loaded from YAML or Marshal files.
21
-
22
9
  ## Installation
23
10
 
24
11
  Add this line to your application's Gemfile:
@@ -33,14 +20,15 @@ Or install it yourself as:
33
20
 
34
21
  $ gem install wrap_in_module
35
22
 
36
- ## Synopsis
23
+ ## Usage:
37
24
 
38
25
  **program.rb:**
39
26
 
40
27
  require 'wrap_in_module'
41
- my_script = WrapInModule::Script.load("my-script.rb")
42
- p my_script::VALUE
43
- my_script.run
28
+ module MyModule
29
+ WrapInModule::wrap_file(MyModule, "my-script.rb")
30
+ p MyModule::VALUE
31
+ MyModule.run
44
32
 
45
33
  **my-script.rb:**
46
34
 
@@ -53,77 +41,72 @@ Or install it yourself as:
53
41
 
54
42
  $ ruby program.rb
55
43
  [1, 2, 3]
56
- #<Script:/tmp/my-script.rb> running.
57
44
 
58
- ## Usage
45
+ ## Detailed Usage
59
46
 
60
- `WrapInModule::Script` modules are instantiated with
61
- <tt>WrapInModule::Script.new(main_file)</tt> or the alias
62
- <tt>WrapInModule::Script.load(main_file)</tt>. All the top-level constants and
63
- top-level methods that are defined in the +main_file+ and its dependent local
64
- files (see below) are scoped in the same Script module, and are thereby
47
+ `WrapInModule::wrap_file(_module, file_path)` wraps the file specified by
48
+ *file_path* under the specified *_module*. All the top-level constants and
49
+ top-level methods that are defined in the file at *file_path* and its dependent
50
+ local files (see below) are scoped in the same module, and are thereby
65
51
  available to the calling program.
66
52
 
67
- The +main_file+ can load or require other files with +load+ and +require+, as
68
- usual. These methods, in the `WrapInModule::Script` context, add some behavior
69
- to the +Kernel+ +load+ and +require+ methods:
70
- <tt>WrapInModule::Script#load</tt> and <tt>WrapInModule::Script#require</tt>
71
- first search for files relative to the +main_file+'s dir. Files loaded in this
72
- way ("dependent local files") are treated like the script file itself:
73
- top-level definitions are added to the script module that is returned by +load+
74
- or +require+.
75
-
76
- Both <tt>WrapInModule::Script#load</tt> and
77
- <tt>WrapInModule::Script#require</tt> fall back to the Kernel versions if the
78
- file is not found locally. Hence, other ruby libraries can be loaded and
79
- required as usual, assuming their names do not conflict with local file names.
80
- Definitions from those files go into the usual scope (typically global). The
81
- normal ruby +load+ and +require+ behavior can be forced by calling
82
- <tt>Kernel.load</tt> and <tt>Kernel.require</tt>.
83
-
84
- A `WrapInModule::Script` immitates the way the top-level ruby context works, so
85
- a ruby file that was originally intended to be run from the top level, defining
86
- top-level constants and top-level methods, can also be run as a
87
- `WrapInModule::Script`, and its top-level constants and top-level methods are
88
- wrapped in the script's scope. The difference between this behavior and simply
89
- wrapping the loaded definitions in an _anonymous_ module using
90
- <tt>Kernel.load(main_file, true)</tt> is that the top-level methods and
91
- top-level constants defined in the script are accessible using the
92
- `WrapInModule::Script` instance.
93
-
94
- The top-level definitions of a `WrapInModule::Script` can be accessed after it
53
+ The file located at *file_path* can load or require other files with *load* and
54
+ *require*, as usual. These methods, in the *_module* context, add some behavior
55
+ to the *Kernel* *load* and *require* methods: Within the *_module* context they
56
+ first search for files relative to the *file_path*'s dir. Files loaded in this
57
+ way ("dependent local files") are treated like the file located at *file_path*:
58
+ top-level definitions are added to the module.
59
+
60
+ Both *load* and *require* fall back to the Kernel versions if the file is not
61
+ found locally. Hence, other ruby libraries can be loaded and required as usual,
62
+ assuming their names do not conflict with local file names. Definitions from
63
+ those files go into the usual scope (typically global). The normal ruby *load*
64
+ and *require* behavior can be forced by calling `Kernel.load` and
65
+ `Kernel.require`.
66
+
67
+ A `WrapInModule` wrapped file immitates the way the top-level ruby
68
+ context works, so a ruby file that was originally intended to be run from the
69
+ top level, defining top-level constants and top-level methods, can also be run
70
+ as a module, and its top-level constants and top-level methods are wrapped in
71
+ the modules scope. The difference between this behavior and simply wrapping the
72
+ loaded definitions in an _anonymous_ module using `Kernel.load(main_file,
73
+ true)` is that the top-level methods and top-level constants defined in the
74
+ module are accessible using the *_module*.
75
+
76
+ The top-level definitions of a `WrapInModule` module can be accessed after it
95
77
  has been loaded, as follows:
96
78
 
97
- <tt>script.meth</tt>
79
+ `module.meth`
80
+
81
+ - Call a method defined using `def meth` or `def self.meth` in the specified
82
+ file.
98
83
 
99
- - Call a method defined using <tt>def meth</tt> or <tt>def self.meth</tt> in
100
- the script file.
84
+ `module::K`
101
85
 
102
- <tt>script::K</tt>
86
+ - Access a class, module, or constant defined using `K = val` in the specified
87
+ file.
103
88
 
104
- - Access a class, module, or constant defined using <tt>K = val</tt> in the
105
- script file.
89
+ ## History
106
90
 
107
- An "input" can be passed to the script before loading. Simply call
108
- `WrapInModule::Script.new` (or `WrapInModule::Script.load`) with a block. The
109
- block is passed a single argument, the `WrapInModule::Script` module, and
110
- executed before the files are loaded into the Script's scope. Setting a
111
- constant in this block makes the constant available to the script during
112
- loading. For example:
91
+ This is largely based on an older script called **script.rb** written by Joel
92
+ VanderWerf and released under the Ruby license in 2004. I found issues with the
93
+ way **script.rb** was doing things, specifically with respect to creating a
94
+ module like object rather than an actual module. This caused problems with
95
+ libraries such as ActiveModel and validations, etc. Therefore, I rewrote it to
96
+ work with normal modules.
113
97
 
114
- script = Script.load("my-script.rb") { |script| script::INPUT = 3 }
98
+ Lots of props have to go out to Joel VanderWerf for writing **script.rb** in
99
+ the first place. It would have taken me a lot longer to accomplish this if I
100
+ didn't have Joel's **script.rb** ruby file to go off of.
115
101
 
116
- Note that all methods defined in the script file are both instance methods of
117
- the module and methods of the module instance (the effect of
118
- <tt>Module#module_function</tt>). So <tt>include</tt>-ing a Script module in a
119
- class will give instances of the class all the methods and constants defined in
120
- the script, and they will reference the instance's instance variables,
121
- rather than the Script module's instance variables.
102
+ Thanks Joel
122
103
 
123
- The Script class was inspired by Nobu Nokada's suggestion in
104
+ It also looks that Joel was originally inspired by Nobu Nokada's suggestion in
124
105
  http://ruby-talk.org/62727, in a thread (started in http://ruby-talk.org/62660)
125
106
  about how to use ruby script files as specifications of objects.
126
107
 
108
+
109
+
127
110
  ## Legal and Contact Information
128
111
 
129
112
  Usable under the Ruby license. Copyright (C)2004 Joel VanderWerf. Questions to
@@ -1,7 +1,9 @@
1
1
  require "wrap_in_module/version"
2
2
 
3
3
  module WrapInModule
4
- # NOTE: The following is coppied out of script.rb v0.3
4
+ # NOTE: The following is rewrite of script.rb v0.3. I had some issues with
5
+ # script.rb v0.3 so I rewrote large portions of it to work with existing
6
+ # modules rather than define pho modules.
5
7
  # For more information please refer to http://redshift.sourceforge.net where
6
8
  # I acquired the script-0.3.tar
7
9
 
@@ -12,128 +14,115 @@ module WrapInModule
12
14
  # much the same way that objects can be loaded from YAML or Marshal files.
13
15
  #
14
16
  # See intro.txt[link:files/intro_txt.html] for an overview.
17
+ #
18
+ class MissingFile < LoadError; end
15
19
 
16
- class Script
17
- # Creates new Script, and loads _main_file_ in the scope of the Script. If a
18
- # block is given, the script is passed to it before loading from the file, and
19
- # constants can be defined as inputs to the script.
20
-
21
- def initialize(_module, main_file) # :yields: self
22
- @__module = _module
23
- @__module.extend LoadInModuleMethods
24
- @__module.extend ScriptModuleMethods
25
-
26
- yield self if block_given?
20
+ def self.wrap_file(_module, _file_path)
21
+ _module.extend ::WrapInModule::LoadInModuleMethods
22
+ _module.module_eval do
23
+ # The file with which the Script was instantiated.
24
+ attr_reader :__main_file
27
25
 
28
- @__module.module_eval do
29
- # The file with which the Script was instantiated.
30
- attr_reader :__main_file
26
+ # The directory in which main_file is located, and relative to which
27
+ # #load searches for files before falling back to Kernel#load.
28
+ attr_reader :__dir
29
+
30
+ # A hash that maps <tt>filename=>true</tt> for each file that has been
31
+ # required locally by the script. This has the same semantics as <tt>$"</tt>,
32
+ # alias <tt>$LOADED_FEATURES</tt>, except that it is local to this script.
33
+ attr_reader :__loaded_features
31
34
 
32
- # The directory in which main_file is located, and relative to which
33
- # #load searches for files before falling back to Kernel#load.
34
- attr_reader :__dir
35
-
36
- # A hash that maps <tt>filename=>true</tt> for each file that has been
37
- # required locally by the script. This has the same semantics as <tt>$"</tt>,
38
- # alias <tt>$LOADED_FEATURES</tt>, except that it is local to this script.
39
- attr_reader :__loaded_features
35
+ @__main_file = File.expand_path(_file_path)
36
+ @__dir = File.dirname(@__main_file)
37
+ @__loaded_features = {}
38
+ load_in_module(@__main_file)
39
+ end
40
+ end
40
41
 
41
- @__main_file = File.expand_path(main_file)
42
- @__dir = File.dirname(@__main_file)
43
- @__loaded_features = {}
44
- load_in_module(main_file)
42
+ module LoadInModuleMethods
43
+ # Loads _file_ in this module's context. Note that <tt>\_\_FILE\_\_</tt> and
44
+ # <tt>\_\_LINE\_\_</tt> work correctly in _file_.
45
+ # Called by #load and #require; not normally called directly.
46
+ def load_in_module(__file__)
47
+ module_eval("@__script_scope ||= binding\n" + IO.read(__file__),
48
+ File.expand_path(__file__), 0)
49
+ # start numbering at 0 because of the extra line.
50
+ # The extra line does nothing in sub-script files.
51
+ rescue Errno::ENOENT
52
+ if /#{__file__}$/ =~ $!.message # No extra locals in this scope.
53
+ # raise MissingFile, $!.message
54
+ raise ::WrapInModule::MissingFile, $!.message
55
+ else
56
+ raise
45
57
  end
46
58
  end
47
59
 
48
- module LoadInModuleMethods
49
- # Loads _file_ in this module's context. Note that <tt>\_\_FILE\_\_</tt> and
50
- # <tt>\_\_LINE\_\_</tt> work correctly in _file_.
51
- # Called by #load and #require; not normally called directly.
52
- def load_in_module(__file__)
53
- module_eval("@__script_scope ||= binding\n" + IO.read(__file__),
54
- File.expand_path(__file__), 0)
55
- # start numbering at 0 because of the extra line.
56
- # The extra line does nothing in sub-script files.
57
- rescue Errno::ENOENT
58
- if /#{__file__}$/ =~ $!.message # No extra locals in this scope.
59
- raise MissingFile, $!.message
60
- else
61
- raise
62
- end
63
- end
60
+ # This is so that <tt>def meth...</tt> behaves like in Ruby's top-level
61
+ # context. The implementation simply calls
62
+ # <tt>Module#module_function(name)</tt>.
63
+ def method_added(name) # :nodoc:
64
+ module_function(name)
64
65
  end
65
66
 
66
- # def to_s # :nodoc:
67
- # "#<#{self.class}:#{File.join(__dir, File.basename(__main_file))}>"
68
- # end
69
-
70
- module ScriptModuleMethods
71
- # This is so that <tt>def meth...</tt> behaves like in Ruby's top-level
72
- # context. The implementation simply calls
73
- # <tt>Module#module_function(name)</tt>.
74
- def method_added(name) # :nodoc:
75
- module_function(name)
76
- end
77
-
78
- attr_reader :__script_scope
67
+ attr_reader :__script_scope
79
68
 
80
- # Gets list of local vars in the script. Does not see local vars in files
81
- # loaded or required by that script.
82
- def __local_variables
83
- eval("local_variables", __script_scope)
84
- end
85
-
86
- # Gets value of local var in the script. Does not see local vars in files
87
- # loaded or required by that script.
88
- def __local_variable_get(name)
89
- eval(name.to_s, __script_scope)
90
- end
69
+ # Gets list of local vars in the script. Does not see local vars in files
70
+ # loaded or required by that script.
71
+ def __local_variables
72
+ eval("local_variables", __script_scope)
73
+ end
74
+
75
+ # Gets value of local var in the script. Does not see local vars in files
76
+ # loaded or required by that script.
77
+ def __local_variable_get(name)
78
+ eval(name.to_s, __script_scope)
79
+ end
91
80
 
92
- # Raised by #load_in_module, caught by #load and #require.
93
- class MissingFile < LoadError; end
94
81
 
95
- # Loads _file_ into this Script. Searches relative to the local dir, that is,
96
- # the dir of the file given in the original call to
97
- # <tt>Script.load(file)</tt>, loads the file, if found, into this Script's
98
- # scope, and returns true. If the file is not found, falls back to
99
- # <tt>Kernel.load</tt>, which searches on <tt>$LOAD_PATH</tt>, loads the file,
100
- # if found, into global scope, and returns true. Otherwise, raises
101
- # <tt>LoadError</tt>.
102
- #
103
- # The _wrap_ argument is passed to <tt>Kernel.load</tt> in the fallback case,
104
- # when the file is not found locally.
105
- #
106
- # Typically called from within the main file to load additional sub files, or
107
- # from those sub files.
108
-
109
- def load(file, wrap = false)
82
+ # Loads _file_ into this Script. Searches relative to the local dir, that is,
83
+ # the dir of the file given in the original call to
84
+ # <tt>Script.load(file)</tt>, loads the file, if found, into this Script's
85
+ # scope, and returns true. If the file is not found, falls back to
86
+ # <tt>Kernel.load</tt>, which searches on <tt>$LOAD_PATH</tt>, loads the file,
87
+ # if found, into global scope, and returns true. Otherwise, raises
88
+ # <tt>LoadError</tt>.
89
+ #
90
+ # The _wrap_ argument is passed to <tt>Kernel.load</tt> in the fallback case,
91
+ # when the file is not found locally.
92
+ #
93
+ # Typically called from within the main file to load additional sub files, or
94
+ # from those sub files.
95
+
96
+ def load(file, wrap = false)
97
+ begin
110
98
  load_in_module(File.join(@__dir, file))
111
99
  true
112
- rescue MissingFile
100
+ rescue ::WrapInModule::MissingFile
113
101
  super
114
102
  end
103
+ end
115
104
 
116
- # Analogous to <tt>Kernel#require</tt>. First tries the local dir, then falls
117
- # back to <tt>Kernel#require</tt>. Will load a given _feature_ only once.
118
- #
119
- # Note that extensions (*.so, *.dll) can be required in the global scope, as
120
- # usual, but not in the local scope. (This is not much of a limitation in
121
- # practice--you wouldn't want to load an extension more than once.) This
122
- # implementation falls back to <tt>Kernel#require</tt> when the argument is an
123
- # extension or is not found locally.
124
-
125
- def require(feature)
105
+ # Analogous to <tt>Kernel#require</tt>. First tries the local dir, then falls
106
+ # back to <tt>Kernel#require</tt>. Will load a given _feature_ only once.
107
+ #
108
+ # Note that extensions (*.so, *.dll) can be required in the global scope, as
109
+ # usual, but not in the local scope. (This is not much of a limitation in
110
+ # practice--you wouldn't want to load an extension more than once.) This
111
+ # implementation falls back to <tt>Kernel#require</tt> when the argument is an
112
+ # extension or is not found locally.
113
+
114
+ def require(feature)
115
+ begin
126
116
  unless @__loaded_features[feature]
127
117
  @__loaded_features[feature] = true
128
118
  file = File.join(@__dir, feature)
129
119
  file += ".rb" unless /\.rb$/ =~ file
130
120
  load_in_module(file)
131
121
  end
132
- rescue MissingFile
122
+ rescue ::WrapInModule::MissingFile
133
123
  @__loaded_features[feature] = false
134
124
  super
135
125
  end
136
126
  end
137
127
  end
138
128
  end
139
-
@@ -1,3 +1,3 @@
1
1
  module WrapInModule
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -3,26 +3,26 @@ require 'spec_helper'
3
3
  describe "WrapInModule" do
4
4
  it "loads a file with a single top level class" do
5
5
  module FooMod; end
6
- WrapInModule::Script.new(FooMod, File.dirname(__FILE__) + '/../example_data/single_top_level_class.rb')
6
+ WrapInModule.wrap_file(FooMod, File.dirname(__FILE__) + '/../example_data/single_top_level_class.rb')
7
7
  FooMod::Hoopty.new
8
8
  end
9
9
 
10
10
  it "loads a file without overwriting existing module definition" do
11
11
  module FooMod; BOB="hello there I am bob"; end
12
- WrapInModule::Script.new(FooMod, File.dirname(__FILE__) + '/../example_data/single_top_level_class.rb')
12
+ WrapInModule.wrap_file(FooMod, File.dirname(__FILE__) + '/../example_data/single_top_level_class.rb')
13
13
  FooMod::BOB
14
14
  end
15
15
 
16
16
  it "loads a file with a top level class that requires another file with a top level class" do
17
17
  module FooMod; end
18
- WrapInModule::Script.new(FooMod, File.dirname(__FILE__) + '/../example_data/top_level_class_requires_another_file.rb')
18
+ WrapInModule.wrap_file(FooMod, File.dirname(__FILE__) + '/../example_data/top_level_class_requires_another_file.rb')
19
19
  FooMod::Doopty.new
20
20
  FooMod::Hoopty.new
21
21
  end
22
22
 
23
23
  it "verify that classes required inside of the top level loaded file are accesible in the non namespaces scope" do
24
24
  module FooMod; end
25
- WrapInModule::Script.new(FooMod, File.dirname(__FILE__) + '/../example_data/top_level_class_requires_another_file.rb')
25
+ WrapInModule.wrap_file(FooMod, File.dirname(__FILE__) + '/../example_data/top_level_class_requires_another_file.rb')
26
26
  a = FooMod::Doopty.new
27
27
  a.test_hoopty
28
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wrap_in_module
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: