namespace 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +37 -0
  2. data/lib/namespace.rb +92 -0
  3. metadata +70 -0
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ Namespaces for ruby <hack>
2
+ ==========================
3
+
4
+ Brings a namespace system to ruby. By loading the .rb files into a temporary
5
+ module, it is possible to avoid polluting the global namespace and select what to import
6
+ in the current module.
7
+
8
+ This system is inspired by the CommonJS module system, but it was adapted
9
+ for the ruby particularities.
10
+
11
+ Feature:
12
+ * Possible to avoid namespace collision on the module level
13
+ * Relative requires (if import is used in the top-level of the file)
14
+
15
+ Unfeatures:
16
+ * uses eval and other nasty ruby hacks
17
+ * classes and namespaces don't mix well because "class X; <<here>>; end"
18
+ is a new context that doesn't inherit from it's parent.
19
+
20
+ TODO
21
+ ----
22
+
23
+ * Handle circular dependencies ?
24
+ * Avoid eval (but I don't see how)
25
+
26
+ Bikeshed
27
+ --------
28
+
29
+ * Should ruby "namespaced" modules have their own $LOAD_PATH and file extensions ?
30
+
31
+ Licence
32
+ -------
33
+
34
+ Public domain
35
+
36
+ Cheers,
37
+ Jonas
data/lib/namespace.rb ADDED
@@ -0,0 +1,92 @@
1
+ # Namespaces for ruby.
2
+ #
3
+ # See Namespace#import
4
+ module Namespace
5
+ @cache = {}
6
+ class << self;
7
+ attr_reader :cache
8
+ include Namespace
9
+ end
10
+
11
+ module Def
12
+ def self.included(mod)
13
+ eigenclass = (class << mod
14
+ # Override to not show Namespace::NS for all modules
15
+ def inspect
16
+ defined?(@__namespace__) ? "<#{@__namespace__} #{(constants+instance_methods).sort.join(', ')}>" : super
17
+ end
18
+ self
19
+ end)
20
+ eigenclass.send(:include, mod, Namespace)
21
+ end
22
+ end
23
+
24
+ #
25
+ # Loads a file according to the +namespace+ in the context of a module,
26
+ # and returns that object.
27
+ #
28
+ # It's not a Python import, where the namespace is available. What you
29
+ # get here, is a sort of Sandbox where constants defined in the file are
30
+ # not polluting the global namespace but available on the returned object.
31
+ # Since the returned object is a Module, it can be included in the current
32
+ # module if you're also in the contect of a "Sandbox".
33
+ #
34
+ # #import has been chosen because the ruby namespace is already crowded
35
+ # (require, load and include are already taken)
36
+ #
37
+ def import(namespace)
38
+ namespace = namespace.to_s.gsub(/[\/\\:]+/, ':') # allow symbols
39
+
40
+ # @__namespace__ is not available outside of the ruby top-level
41
+ if defined?(@__namespace__) && namespace[0..0] != ":"
42
+ # expand namespace
43
+ namespace = @__namespace__.sub(/:[^:]+$/,'') + ':' + namespace
44
+ else
45
+ namespace = ':' + namespace
46
+ end
47
+ puts "ns##{namespace}"
48
+
49
+ # Cache lookup
50
+ ns = Namespace::cache[namespace]
51
+ return ns if ns
52
+
53
+ file = nil
54
+ # File lookup
55
+ file_path = namespace[1..-1].gsub(':', File::SEPARATOR) + '.rb'
56
+ $LOAD_PATH.each do |path|
57
+ path = File.join(path, file_path)
58
+ if File.exists? path
59
+ file = path
60
+ break
61
+ end
62
+ end
63
+
64
+ raise LoadError, "no such file to load -- #{file_path}" unless file
65
+
66
+ file_content = File.read(file_path)
67
+ # Pre-process __NAMESPACE__ keyword to act like __FILE__
68
+ # in know... it's not exactly the same... (eg "__FILE__") but it should do the trick
69
+ file_content.gsub!('__NAMESPACE__', namespace.inspect)
70
+
71
+ # Make sure NS is new (in the cases where the current NS requires another NS)
72
+ Object.send(:remove_const, :NS) rescue nil
73
+ # String is on 1 line to make sure line-errors are preserved
74
+ ns = eval("module NS; @__namespace__ = #{namespace.inspect}; include Namespace::Def; #{file_content}; self; end", TOPLEVEL_BINDING, file)
75
+
76
+ # Cache
77
+ Namespace::cache[namespace] = ns
78
+
79
+ return ns
80
+ ensure
81
+ Object.send(:remove_const, :NS) rescue nil
82
+ end
83
+ end
84
+
85
+ # Make #import available to all
86
+ class Object; include Namespace; end
87
+
88
+ if __FILE__ == $0
89
+ require 'irb'
90
+ require 'irb/completion'
91
+ IRB.start
92
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: namespace
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ version: "1.0"
10
+ platform: ruby
11
+ authors:
12
+ - Jonas Pfenniger
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-20 00:00:00 +00:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: |-
22
+ This module is a hack that allows you to load specific
23
+ ruby files in the context of a Module, thus avoiding global namespace
24
+ pollution
25
+ email: jonas@pfenniger.name
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - README.md
34
+ - lib/namespace.rb
35
+ has_rdoc: true
36
+ homepage: https://github.com/zimbatm/namespace.rb
37
+ licenses: []
38
+
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.7
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Bringing namespaces to Ruby
69
+ test_files: []
70
+