alki-loader 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 35748f34edecf67d26bc0a7e3cf369c37a1316a6
4
+ data.tar.gz: c76640c73518c34797723b12cf3dc2fc0918fde5
5
+ SHA512:
6
+ metadata.gz: 6d83c0157460cb42a860563d557a478476b3c6d3fa41001917cc9d8c7acdd529d6ea021affbacf0fdb4ea02ccd734e974016b697879f4eb3a827a4626f80b849
7
+ data.tar.gz: a813aea0fa6d21cc84dfc8cdeb6cc4cab609a8cd59f59d57adbf269b060879d06731334344993c24d8f51cac02a80fd1dffe1e99f711e229757863908b3ba6b8
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at matt.edlefsen@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in alki-loader.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Matt Edlefsen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.adoc ADDED
@@ -0,0 +1,124 @@
1
+ # Alki::Loader
2
+
3
+ Alki loader is a library for using "non-standard" source files in your project. What is
4
+ a non-standard source file?
5
+
6
+ Generally a ruby source file follows these rules:
7
+
8
+ 1. It should be placed in a directory that is in `$LOAD_PATH`, so that it can be loaded using `require`.
9
+ 2. It should define one ore more constants.
10
+ 3. Ideally, it should just define a constant that is the "classified" version of the relative path of the
11
+ file (if a directory `/project/lib` is in `$LOAD_DIR` and there is a file called `/project/lib/my_mod/my_class.rb`
12
+ then the constant defined within it should be `MyMod::MyClass`).
13
+
14
+ This works well much of the time, but often enough it's nice to break some of these rules.
15
+ For example, you might want files in directories in your project like `config` or `app` but don't want
16
+ to add those to `$LOAD_PATH` because it could cause conflicts, or maybe you have files that you don't
17
+ want to just define a module or class (like a DSL).
18
+
19
+ Alki::Loader provides tools that enable these patterns while still allowing you to use these files
20
+ in standard ways.
21
+
22
+ There are three main components of Alki::Loader:
23
+
24
+ Translater:: Allows registering directory and file paths with fake "names" so, for example, your
25
+ projects `config` directory could be registered with the name `my_project/config`. Now
26
+ when calling `require 'my_project/config/my_config'` Ruby will load `config/my_config.rb`
27
+ (but `require 'my_config'` will still find nothing).
28
+
29
+ Builder:: Allows registering directory and file paths with "builder" objects and configuration values.
30
+ Files under these paths put their code in an unevaluated block that is passed to the builder
31
+ so that it can process it and ultimately define the expected constant for that path with
32
+ a value.
33
+
34
+ Registry:: To allow the other two components to work, paths must be registered with Alki::Loader. This
35
+ can be done anytime in code but can also be set by putting register calls in an `alk_loader.rb`
36
+ file in any directory in `$LOAD_PATH`.
37
+
38
+ ## Installation
39
+
40
+ Add this line to your application's Gemfile:
41
+
42
+ ```ruby
43
+ gem 'alki-loader'
44
+ ```
45
+
46
+ And then execute:
47
+
48
+ $ bundle
49
+
50
+ Or install it yourself as:
51
+
52
+ $ gem install alki-loader
53
+
54
+ ## Usage
55
+
56
+ ```ruby
57
+ require 'alki/loader'
58
+ ```
59
+
60
+ Once the library is required you can require files as you normally would.
61
+
62
+ To register a path, use `Alki::Loader.register(path,settings)`. This can be called anywhere at any
63
+ time, but to make sure your paths are registered before they're needed, it's best to use an
64
+ `alki_loader.rb` file.
65
+
66
+ To use one create a `alki_loader.rb` file in whatever directory in your project is in `$LOAD_PATH`
67
+ (typically `lib`). It should just contain normal `Alki::Loader.register` calls.
68
+
69
+ The path argument to register should either be an absolute path, or a path relative to directory of the
70
+ calling file (if you have `Alki::Loader.register '../config', ... ` in `lib/alki_loader.rb` it will
71
+ register `config`).
72
+
73
+ If path registrations exist for multiple prefixes of the same file, the longest one will be used.
74
+
75
+ ### Settings
76
+
77
+ When registering a path, the second argument is hash of settings to configure the path. These can be
78
+ arbitrary key/value pairs but there are two setting values with special meaning.
79
+
80
+ [horizontal]
81
+ name:: Provide a name for the translater to use for this path. Will translate just the registered
82
+ path and leave the rest of the path the same when changed.
83
+ builder:: Set the builder object, if one is wanted. Can be any object with a `build` method or a require
84
+ path where a constant can be found that has a build class method (`my_project/my_builder` will
85
+ attempt to find `MyProject::MyBuilder` and will call `require 'my_project/my_builder'`
86
+ to try and find it).
87
+
88
+ ### Builders
89
+
90
+ A file that is to be built using a builder should always be in an Alki block:
91
+
92
+ .my_file.rb
93
+ ```ruby
94
+ Alki do
95
+ # stuff goes here
96
+ end
97
+ ```
98
+
99
+ When the file is loaded, the builder object registered for the path will be called like so:
100
+
101
+ ```ruby
102
+ builder.build settings, &blk
103
+ ```
104
+
105
+ Where `blk` is the unevaluated block from the file, and `settings` is a hash containing all of the
106
+ settings registered to the path, along with two extra settings so the builder knows what file it's
107
+ building.
108
+
109
+ [horizontal]
110
+ name:: What would be passed to `require` to load the file. If the file is in a `$LOAD_PATH` directory
111
+ it will be the relative path from the directory minus the '.rb'. If there is name translation
112
+ registered on the path, that will be used instead.
113
+ constant_name:: The "class-ified" version of the name, following the typical rules for translating
114
+ require paths into constant names. No special rules are used for abbreviations.
115
+
116
+ ## Contributing
117
+
118
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alki-project/alki-loader. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
119
+
120
+
121
+ ## License
122
+
123
+ The gem is available as open source under the terms of the http://opensource.org/licenses/MIT[MIT License].
124
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'alki/loader/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "alki-loader"
8
+ spec.version = Alki::Loader::VERSION
9
+ spec.authors = ["Matt Edlefsen"]
10
+ spec.email = ["matt.edlefsen@gmail.com"]
11
+
12
+ spec.summary = %q{Library for loading non-traditional ruby files}
13
+ spec.homepage = "https://github.com/alki-project/alki-loader"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.13"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "minitest", "~> 5.9"
26
+ spec.add_dependency "alki-support", "~> 0.7"
27
+ end
@@ -0,0 +1,67 @@
1
+ require 'alki/support'
2
+ require 'alki/loader/registry'
3
+ require 'alki/loader/entry'
4
+ require 'alki/loader/core_ext/kernel'
5
+
6
+ module Alki
7
+ module Loader
8
+ LoaderError = Class.new(StandardError)
9
+
10
+ @registry = Alki::Loader::Registry.new
11
+
12
+ def self.registered_paths
13
+ @registry.paths
14
+ end
15
+
16
+ def self.translate(name)
17
+ entry = @registry.lookup_name(name)
18
+ if entry
19
+ entry.path + name[entry.name.size..-1]
20
+ end
21
+ end
22
+
23
+ def self.lookup_name(path)
24
+ path_name @registry.lookup_path(path), path
25
+ end
26
+
27
+ def self.build(path,builder=nil,data=nil,&blk)
28
+ entry = @registry.lookup_path(path)
29
+ unless entry
30
+ raise LoaderError.new("No path registered for #{path}")
31
+ end
32
+ builder ||= entry.data[:builder]
33
+ unless builder
34
+ raise LoaderError.new("No builder registered for #{path}")
35
+ end
36
+ name = path_name(entry, path) or
37
+ raise LoaderError.new("Path not registered with name or in $LOAD_PATH #{path}")
38
+ data ||= entry.data
39
+ builder = Alki::Support.load builder
40
+ builder.build data.merge(name: name, constant_name: Alki::Support.classify(name)), &blk
41
+ end
42
+
43
+ def self.register(path,**data)
44
+ unless path.start_with? '/'
45
+ caller_dir = File.dirname(caller_locations(1,1)[0].absolute_path)
46
+ path = File.expand_path(path,caller_dir)
47
+ end
48
+ @registry.add Entry.new(path,data)
49
+ end
50
+
51
+ private
52
+
53
+ def self.path_name(entry,path)
54
+ if entry && entry.name
55
+ name = entry.name + path[entry.path.size..-1]
56
+ else
57
+ dir = $LOAD_PATH.find{|d| path.start_with?(File.join(d,''))}
58
+ unless dir
59
+ return nil
60
+ end
61
+ name = path[File.join(dir,'').size..-1]
62
+ end
63
+ name.chomp!('.rb')
64
+ name
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,24 @@
1
+ require 'alki/loader'
2
+
3
+ module Kernel
4
+ alias_method :__alki_loader_original_require, :require
5
+
6
+ def require(name)
7
+ __alki_loader_original_require name
8
+ rescue LoadError => e
9
+ translated = Alki::Loader.translate(name)
10
+ if translated
11
+ __alki_loader_original_require translated
12
+ else
13
+ raise e
14
+ end
15
+ end
16
+
17
+ def Alki(builder=nil,data=nil,&blk)
18
+ if blk
19
+ path = caller_locations(1,1)[0].absolute_path
20
+ Alki::Loader.build path, builder, data, &blk
21
+ end
22
+ ::Alki
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ module Alki
2
+ module Loader
3
+ class Entry
4
+ attr_reader :path
5
+ attr_reader :data
6
+
7
+ def initialize(path,data)
8
+ @path = path.chomp('/')
9
+ @data = data
10
+ end
11
+
12
+ def name
13
+ @data[:name]
14
+ end
15
+
16
+ def build(blk)
17
+ Alki::Support.load_class(@builder).build @data, &blk
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
1
+ module Alki
2
+ module Loader
3
+ class Registry
4
+ def initialize
5
+ clear
6
+ end
7
+
8
+ def clear
9
+ @paths = []
10
+ @paths_sorted = true
11
+ @names = []
12
+ @names_sorted = true
13
+ @configs_loaded = false
14
+ end
15
+
16
+ def paths
17
+ load_configs!
18
+ @paths.map{|e| e.path }
19
+ end
20
+
21
+ def add(entry)
22
+ @paths.delete_if{|e| e.path == entry.path }
23
+ @paths << entry
24
+ if entry.name
25
+ @names.delete_if{|e| e.path == entry.path }
26
+ @names << entry
27
+ end
28
+ end
29
+
30
+ def lookup_name(name)
31
+ load_configs!
32
+ unless @names_sorted
33
+ @names.sort! {|a,b| b.name <=> a.name }
34
+ @names_sorted = true
35
+ end
36
+ @names.find do |e|
37
+ name.start_with?(e.name) &&
38
+ (name.size == e.name.size || name[e.name.size] == '/')
39
+ end
40
+ end
41
+
42
+ def lookup_path(path)
43
+ load_configs!
44
+ unless @paths_sorted
45
+ @paths.sort! {|a,b| b.path <=> a.path }
46
+ @paths_sorted = true
47
+ end
48
+ @paths.find do |e|
49
+ path.start_with?(e.path) &&
50
+ (path.size == e.path.size || path[e.path.size] == '/')
51
+ end
52
+ end
53
+
54
+ def load_configs!
55
+ path_hash = $LOAD_PATH.hash
56
+ return if @configs_loaded == path_hash
57
+ @configs_loaded = path_hash
58
+ Gem.find_files_from_load_path('alki_loader.rb').each do |config_path|
59
+ require config_path
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ module Alki
2
+ module Loader
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alki-loader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matt Edlefsen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-12-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: alki-support
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.7'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.7'
69
+ description:
70
+ email:
71
+ - matt.edlefsen@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - CODE_OF_CONDUCT.md
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.adoc
81
+ - Rakefile
82
+ - alki-loader.gemspec
83
+ - lib/alki/loader.rb
84
+ - lib/alki/loader/core_ext/kernel.rb
85
+ - lib/alki/loader/entry.rb
86
+ - lib/alki/loader/registry.rb
87
+ - lib/alki/loader/version.rb
88
+ homepage: https://github.com/alki-project/alki-loader
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.5.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Library for loading non-traditional ruby files
112
+ test_files: []