outil 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a3cfe1efb43ae4eb0bf954722310c091cfa0fbd3
4
+ data.tar.gz: 5f00fa7f90c1894982e0f3112c55fbea676e4e0c
5
+ SHA512:
6
+ metadata.gz: eb6a368e983db65fa663bc7036444a3e1c9faaeafa7e681c3ac229d1289aeabc1a858a1aa9d5aaa619937a2609094425d023276c54ddcbef1a9d90df508b65a9
7
+ data.tar.gz: 3fdd16515f75d37b7da50785d75ba397c7212bc3423fe0bb3e29d17660db7da2d3ee750b1a0f89b5372922e9d0b72e21d734900d655422a75107ab9ce27ea497
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
3
+ require 'outil'
4
+
5
+ puts ARGV
6
+ Outil::OCS.bootstrap(:index => ARGV[1], :config => ARGV[2])
7
+
@@ -0,0 +1,108 @@
1
+ require 'bundler/setup'
2
+ require 'ruby_decorators'
3
+ require 'parser/current'
4
+ require 'unparser'
5
+ require 'yaml'
6
+
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+
9
+ require 'outil/version'
10
+ require 'outil/decorators'
11
+ require 'outil/workspace'
12
+ require 'outil/ocs'
13
+ require 'outil/ocs/index'
14
+ require 'outil/ocs/config'
15
+ require 'outil/ocs/parser'
16
+
17
+ module Outil
18
+
19
+ def self.index
20
+ Workspace.ocs.index
21
+ end
22
+
23
+ def self.reset!
24
+ Workspace.reset!
25
+ end
26
+
27
+ def self.included(base)
28
+ # Add the decorator class-method logic to the includer
29
+ # E.G. The client has control over the "use" and "named"
30
+ # class-level directives.
31
+
32
+ base.extend(Inferace)
33
+
34
+ # By default, only the Registration decorator
35
+ # is added, and it's added under the generic :outil namespace
36
+
37
+ base.class_eval do
38
+ use Decorators::Register
39
+ named :outil
40
+ end
41
+
42
+ # Pull all the AST's in the user index
43
+ # and define them as methods of the Bucket
44
+ # module just before the inclusion is done.
45
+
46
+ Workspace.ocs.index.all.each do |ast|
47
+ Outil.module_eval <<-RUBY_EVAL
48
+ #{Unparser.unparse(ast)}
49
+ RUBY_EVAL
50
+ end
51
+ end
52
+
53
+ module Inferace
54
+ # BucketInterface is a basically
55
+ # a module mirror of the RubyDecorators::Interface
56
+ # class. To avoid adding dependencies, and increasing
57
+ # the sheer volume of hacks at work here, the Interface
58
+ # code is essentially copied and pasted here as module
59
+ # instance variables
60
+
61
+ include RubyDecorators
62
+
63
+ def self.decorate
64
+ RubyDecorators::Stack.all << self
65
+ Workspace.sync
66
+ end
67
+
68
+ def named(name)
69
+ @name = name.to_s
70
+ class_eval <<-RUBY_EVAL
71
+ def self.#{@name}(dcr)
72
+ if decorators[dcr]
73
+ self.decorate(decorators[dcr])
74
+ end
75
+ end
76
+ RUBY_EVAL
77
+ end
78
+
79
+ def name
80
+ @name ||= self.class.name.to_s
81
+ end
82
+
83
+ def decorators
84
+ @decorators ||= {}
85
+ end
86
+
87
+ def use *decs
88
+ append = Proc.new do |dec|
89
+ fmt = dec.name.split('::').last.
90
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
91
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
92
+ tr("-", "_").
93
+ downcase.
94
+ to_sym
95
+ self.decorators[fmt] = dec
96
+ end
97
+ decs.each &append
98
+ end
99
+
100
+ def registered_methods
101
+ @registered_methods ||= {}
102
+ end
103
+
104
+ def self.registered_decorators
105
+ @registered_decorators ||= {}
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,30 @@
1
+ module Outil
2
+ module Decorators
3
+
4
+ class Register < RubyDecorators::Decorator
5
+
6
+ def call(this, *args, &blk)
7
+ Outil::Workspace.scan *this.source_location << this.name
8
+ this.call(*args, &blk)
9
+ end
10
+
11
+ end
12
+
13
+ class NameSpace
14
+
15
+ def initialize(namespace)
16
+ @namespace = namespace
17
+ end
18
+
19
+ def call(this, *args, &blk)
20
+ # TODO
21
+ # Intended behavior is to register the decorated
22
+ # method under a given namespace, so you can
23
+ # have two methods named the same thing, etc.
24
+ this.call(*args, &blk)
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module Outil
2
+
3
+ module OCS
4
+
5
+ # Object Control System
6
+
7
+ class << self
8
+
9
+ def config(params={})
10
+ @config ||= Config.new(params)
11
+ end
12
+
13
+ def bootstrap options={}
14
+ options.merge! Config.new().params
15
+ Dir.mkdir(options[:index]) unless Dir.exists?(options[:index])
16
+ File.open(options.delete(:path), 'w+') do |f|
17
+ f.write options.to_yaml
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,51 @@
1
+ module Outil
2
+ module OCS
3
+ class Config
4
+
5
+ INDEX_PATH = '.outil'
6
+ CONFIG_PATH = '.outil.rc'
7
+
8
+ def self.home_path
9
+ @home_path ||= File.expand_path(
10
+ File.expand_path(ENV['HOME'] || '~'))
11
+ end
12
+
13
+ attr :params
14
+
15
+ def initialize(params={})
16
+ @params = params
17
+ infer = Proc.new do |key, const|
18
+ @params[key] = "#{self.class.home_path}/#{const}"
19
+ end
20
+ infer.call(:index, INDEX_PATH)
21
+ infer.call(:path, CONFIG_PATH)
22
+ end
23
+
24
+ def options
25
+ @options ||= (
26
+ unless File.exists?(@params[:path])
27
+ raise StandardError "Could not locate your Outil Config File"
28
+ end
29
+ indifference = Proc.new do |hash, x|
30
+ hash[x.first] = x.last
31
+ hash[x.first.to_sym] = x.last
32
+ hash
33
+ end
34
+ YAML.load_file(@params[:path])
35
+ .inject(Hash.new, &indifference)
36
+ )
37
+ end
38
+
39
+ def index
40
+ @index ||= (
41
+ unless options[:index]
42
+ raise StandardError "Could not locate your Outil Index Path"
43
+ end
44
+ Index.new(:path => options[:index])
45
+ )
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,68 @@
1
+ module Outil
2
+ module OCS
3
+ class Index
4
+
5
+ attr :path
6
+
7
+ def initialize params={}
8
+ @path = params[:path]
9
+ end
10
+
11
+ def index_path
12
+ @index_path ||= "#{@path}/index"
13
+ end
14
+
15
+ def append name, ast
16
+ write_serialize name, ast
17
+ update_index name
18
+ end
19
+
20
+ def write_serialize name, ast
21
+ File.open("#{@path}/#{name}.ast", 'w+') do |file|
22
+ file.write ast.to_yaml
23
+ end
24
+ end
25
+
26
+ def indexed_names
27
+ File.open(index_path, 'r') do |f|
28
+ f.read.split(/\n/)
29
+ end.map(&:strip)
30
+ end
31
+
32
+ def update_index name
33
+ return if indexed_names.include?(name.to_s)
34
+ File.open(index_path, 'a') do |file|
35
+ file.write name.to_s << "\n"
36
+ end
37
+ end
38
+
39
+ def read(name)
40
+ File.open("#{@path}/#{name}.ast", 'r') do |file|
41
+ YAML.load(file.read)
42
+ end
43
+ end
44
+
45
+ def all
46
+ indexed_names.map do |name|
47
+ read name
48
+ end
49
+ end
50
+
51
+ def read_exec(name)
52
+ instance_eval <<-RUBY_EVAL
53
+ #{Unparser.unparse(read(name))}
54
+ RUBY_EVAL
55
+ end
56
+
57
+ def hard_reset!
58
+ Dir["#{@path}/*.ast"].each do |path|
59
+ File.delete path
60
+ end
61
+ File.open(index_path, 'w+') do |file|
62
+ file.write String.new
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,63 @@
1
+ module Outil
2
+ module OCS
3
+ class ObjectParser
4
+
5
+ attr :name, :path, :found
6
+
7
+ def initialize(path, name)
8
+ @path = path
9
+ @name = name
10
+ @found = false
11
+ end
12
+
13
+ def node
14
+ @node ||= Parser::CurrentRuby.parse(
15
+ File.open(@path, 'r') do |f|
16
+ f.read
17
+ end
18
+ )
19
+ end
20
+
21
+ def find
22
+ return @found if @found
23
+ set_and_stop = Proc.new do |node|
24
+ return @found = node
25
+ end
26
+ traverse = Proc.new do |node|
27
+ # if we're not at a node, we can move on
28
+ next unless node.is_a?(Parser::AST::Node)
29
+ # unless we're at a method definition
30
+ # we're probably in a begin block, a class, or module
31
+ # in which case traverse the children of the current node
32
+ node.children.each &traverse unless [:defs, :def].include?(node.type)
33
+ # bottom-level node interrogation...
34
+ case node.type
35
+ when :defs
36
+ # class methods
37
+ set_and_stop.call(node) if node.children[1] == name
38
+ next
39
+ when :def
40
+ # instance method
41
+ set_and_stop.call(node) if node.children.first == name
42
+ next
43
+ else
44
+ # other kind of object
45
+ if node.is_a?(Parser::AST::Node)
46
+ # another parent node
47
+ node.children.each &traverse
48
+ else
49
+ # the bottom of a node
50
+ next
51
+ end
52
+ end
53
+ end
54
+ begin
55
+ traverse.call(node)
56
+ rescue
57
+ false
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ module Outil
2
+ module OCS
3
+ class Serialize
4
+ # TODO: Move the Index away from YAML and toward Binary
5
+ # I want to get away from using YAML
6
+ # dumps AST Node class as a serialization method
7
+ # and the nature of AST's themselves make
8
+ # them really friendly to binary serialization.
9
+ # In theory anyway.
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Outil
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,35 @@
1
+ module Outil
2
+
3
+ class Workspace
4
+
5
+ def self.ocs
6
+ @ocs ||= OCS::Config.new
7
+ end
8
+
9
+ def self.reset!
10
+ @references = []
11
+ @asts = {}
12
+ end
13
+
14
+ def self.references
15
+ @references ||= []
16
+ end
17
+
18
+ def self.asts
19
+ @asts ||= {}
20
+ end
21
+
22
+ def self.scan path, lineno, name
23
+ references << [path, lineno, name]
24
+ asts[name] = OCS::ObjectParser.new(path, name).find
25
+ end
26
+
27
+ def self.sync
28
+ asts.each_pair do |name, tree|
29
+ ocs.index.append name, tree
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Outil::Decorators do
4
+
5
+ describe Outil::Decorators::Register do
6
+
7
+ describe "call" do
8
+
9
+ it "should update workspace references" do
10
+ Outil.reset!
11
+ class DummyInterfaceTwo < RubyDecorators::Interface
12
+ use Outil::Decorators::Register
13
+ named :outil
14
+
15
+ outil :register
16
+ def baz
17
+ 'bar'
18
+ end
19
+ end
20
+ DummyInterfaceTwo.new.baz
21
+ target = [[__FILE__, 18, :baz]]
22
+ Outil::Workspace.references.should eq target
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,111 @@
1
+ require 'rubygems'
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
+
5
+ describe Outil::OCS::Index do
6
+
7
+ before do
8
+ @config = Outil::OCS::Config.new
9
+ @index = @config.index
10
+ end
11
+
12
+ describe "initialize" do
13
+ it "should set path instance variable" do
14
+ @index.path.should eq(@config.params[:index])
15
+ end
16
+ end
17
+
18
+ describe "index_path" do
19
+ it "should return the path with index at the end" do
20
+ @index.index_path.should eq(@config.params[:index] + "/index")
21
+ end
22
+ end
23
+
24
+ describe "write_serialize" do
25
+ it "should write a file named for the method to the index" do
26
+ @index.write_serialize(:hello, build_target_ast)
27
+ Dir["#{@index.path}/*.ast"].map do |path|
28
+ File.basename path
29
+ end.include?("hello.ast")
30
+ .should eq(true)
31
+ end
32
+ end
33
+
34
+ describe "indexed_names" do
35
+ it "return a list of registered methods names" do
36
+ @index.write_serialize(:hello, build_target_ast)
37
+ @index.indexed_names.include?("hello").should eq(true)
38
+ end
39
+ end
40
+
41
+ describe "update_index" do
42
+ it "adds a method name to the end of the index file" do
43
+ @index.write_serialize(:dummy, build_target_ast(:dummy))
44
+ @index.update_index :dummy
45
+ @index.indexed_names.include?('dummy').should eq(true)
46
+ end
47
+ end
48
+
49
+ describe "read" do
50
+ it "return an ast for the specified method" do
51
+ @index.write_serialize(:dummy, build_target_ast(:dummy))
52
+ @index.update_index :dummy
53
+ @index.read(:dummy).is_a?(Parser::AST::Node).should eq(true)
54
+ end
55
+ end
56
+
57
+ describe "append" do
58
+
59
+ before do
60
+ @index.append :baz, build_target_ast(:baz)
61
+ end
62
+
63
+ it "should write a file named for the method to the index" do
64
+ @index.indexed_names.include?('baz').should eq(true)
65
+ end
66
+
67
+ it "adds a method name to the end of the index file" do
68
+ Dir["#{@index.path}/*.ast"].map do |path|
69
+ File.basename path
70
+ end.include?("baz.ast")
71
+ .should eq(true)
72
+ end
73
+ end
74
+
75
+ describe "all" do
76
+ it "should return an array of asts" do
77
+ all_ast = Proc.new do |response|
78
+ response.map {|x| x.is_a?(Parser::AST::Node)}
79
+ .uniq == [true]
80
+ end
81
+ all_ast.call(@index.all)
82
+ end
83
+ end
84
+
85
+ describe "read_exec" do
86
+ it "should produce a method" do
87
+ @index.read_exec(:hello)
88
+ @index.send(:hello).should eq('hello')
89
+ end
90
+ end
91
+
92
+ describe "update_index" do
93
+ it "should append method names to the index file" do
94
+ # initialize the interface a bunch and call the
95
+ # registered methods, to make sure they don't keep
96
+ 10.times do
97
+ DummyInterface.new.hello
98
+ DummyInterface.new.goodbye
99
+ end
100
+ target = ['hello', 'dummy']
101
+ include_all = Proc.new do |a,b|
102
+ a.map {|x| b.include?(x) }.uniq == [true]
103
+ end
104
+ indexed = @index.indexed_names
105
+ include_all.call(target,
106
+ indexed)
107
+ .should eq(true)
108
+
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
+
5
+ describe Outil do
6
+
7
+ before do
8
+
9
+ class MyClient
10
+ include Outil
11
+
12
+ outil :register
13
+ def foo
14
+ 'bar'
15
+ end
16
+ end
17
+
18
+ Outil::Workspace.sync
19
+ end
20
+
21
+ describe "included" do
22
+ it "should include registered methods" do
23
+ client = MyClient.new
24
+ client.hello.should eq('hello')
25
+ client.goodbye.should eq('goodbye')
26
+ end
27
+
28
+ it "should allow registration for its own methods" do
29
+ Outil::Workspace.ocs.index.indexed_names.include?('foo').should eq(true)
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,61 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Outil::OCS::ObjectParser do
4
+
5
+ before do
6
+ Outil.reset!
7
+ DummyInterface.new.hello
8
+ @target = build_target_ast
9
+ end
10
+
11
+ after do
12
+ Outil.reset!
13
+ end
14
+
15
+ describe "append" do
16
+ it "append ast to workspace" do
17
+ Outil::Workspace.asts[:hello].should eq(@target)
18
+ end
19
+ end
20
+
21
+ describe "initialize" do
22
+ before do
23
+ @parser = Outil::OCS::ObjectParser.new(__FILE__, :hello)
24
+ end
25
+
26
+ it "should set path" do
27
+ @parser.path.should eq(__FILE__)
28
+ end
29
+
30
+ it "should set name" do
31
+ @parser.name.should eq(:hello)
32
+ end
33
+ end
34
+
35
+ describe "node" do
36
+ before do
37
+ @parser = build_generic_parser
38
+ end
39
+
40
+ it "should return an ast" do
41
+ @parser.node.is_a?(Parser::AST::Node).should eq(true)
42
+ end
43
+ end
44
+
45
+ describe "find" do
46
+ before do
47
+ @parser = build_generic_parser
48
+ end
49
+
50
+ it "should locate the named method in the parse tree" do
51
+ @parser.find.should eq(build_target_ast)
52
+ end
53
+
54
+ it "should set the found instance variable" do
55
+ @parser.find
56
+ @parser.found.should eq(build_target_ast)
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../../lib/outil', __FILE__)
2
+ require 'rspec'
3
+ require 'rspec/expectations'
4
+
5
+ def build_target_ast(name=false)
6
+ name = name ? name : :hello
7
+ Parser::AST::Node.new(:def,
8
+ children=[name,
9
+ Parser::AST::Node.new(:args),
10
+ Parser::AST::Node.new(:str,
11
+ children=["hello"])])
12
+ end
13
+
14
+ def build_generic_parser
15
+ Outil::OCS::ObjectParser
16
+ .new("#{File.dirname(__FILE__)}/spec_helper.rb",
17
+ :hello)
18
+ end
19
+
20
+
21
+ class DummyInterface < RubyDecorators::Interface
22
+ use Outil::Decorators::Register
23
+ named :outil
24
+
25
+ outil :register
26
+ def hello
27
+ 'hello'
28
+ end
29
+
30
+ outil :register
31
+ def goodbye
32
+ 'goodbye'
33
+ end
34
+
35
+ end
36
+
37
+ DummyInterface.new.hello
38
+
39
+ Outil::Workspace.sync
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: outil
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Matt Aliabadi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: parser
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0.beta5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0.beta5
41
+ - !ruby/object:Gem::Dependency
42
+ name: unparser
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Outil is a library for storing and importing reusable code
56
+ email:
57
+ - mattmaliabadi@gmail.com
58
+ executables:
59
+ - outil-boostrap
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - bin/outil-boostrap
64
+ - lib/outil/decorators.rb
65
+ - lib/outil/ocs/config.rb
66
+ - lib/outil/ocs/index.rb
67
+ - lib/outil/ocs/parser.rb
68
+ - lib/outil/ocs/serialize.rb
69
+ - lib/outil/ocs.rb
70
+ - lib/outil/version.rb
71
+ - lib/outil/workspace.rb
72
+ - lib/outil.rb
73
+ - spec/decorator_spec.rb
74
+ - spec/index_spec.rb
75
+ - spec/outil_spec.rb
76
+ - spec/parser_spec.rb
77
+ - spec/spec_helper.rb
78
+ homepage: http://www.github.com/maliabadi/outil
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.0.6
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Stores persistently available utility functions
102
+ test_files: []