alki-dsl 0.3.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: 509cf74d2d757a7d980460a7bd63199e0cfabe39
4
+ data.tar.gz: 33c3f48bac58f19f73f7469ec42f4357cd2321b6
5
+ SHA512:
6
+ metadata.gz: 2ad60f1b2f6c8f012e41c61ff18171ff1fafb65af694c04a96dc15c20ba664c88b60e25d9fc23cf430f7c41396509b7443169ef9f447af2af46e27114255894c
7
+ data.tar.gz: 1245f5d5471641f77603f23aac033fd273f9a622f327fb19ce2268616a9a1c6fb968d589e602f1294a28f69596d0a786242e035d8d5cdbe8bfdc9decca40ec40
data/.gitignore ADDED
@@ -0,0 +1,53 @@
1
+ # Created by .ignore support plugin (hsz.mobi)
2
+ ### Ruby template
3
+ *.gem
4
+ *.rbc
5
+ /.config
6
+ /coverage/
7
+ /InstalledFiles
8
+ /pkg/
9
+ /spec/reports/
10
+ /spec/examples.txt
11
+ /test/tmp/
12
+ /test/version_tmp/
13
+ /tmp/
14
+
15
+ # Used by dotenv library to load environment variables.
16
+ # .env
17
+
18
+ ## Specific to RubyMotion:
19
+ .dat*
20
+ .repl_history
21
+ build/
22
+ *.bridgesupport
23
+ build-iPhoneOS/
24
+ build-iPhoneSimulator/
25
+
26
+ ## Specific to RubyMotion (use of CocoaPods):
27
+ #
28
+ # We recommend against adding the Pods directory to your .gitignore. However
29
+ # you should judge for yourself, the pros and cons are mentioned at:
30
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
31
+ #
32
+ # vendor/Pods/
33
+
34
+ ## Documentation cache and generated files:
35
+ /.yardoc/
36
+ /_yardoc/
37
+ /doc/
38
+ /rdoc/
39
+
40
+ ## Environment normalization:
41
+ /.bundle/
42
+ /vendor/bundle
43
+ /lib/bundler/man/
44
+
45
+ # for a library or gem, you might want to ignore these files since the code is
46
+ # intended to run in multiple environments; otherwise, check them in:
47
+ Gemfile.lock
48
+ # .ruby-version
49
+ # .ruby-gemset
50
+
51
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
52
+ .rvmrc
53
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/alki-dsl.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ require_relative 'lib/alki/dsl/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "alki-dsl"
6
+ spec.version = Alki::Dsl::VERSION
7
+ spec.authors = ["Matt Edlefsen"]
8
+ spec.email = ["matt.edlefsen@gmail.com"]
9
+ spec.summary = %q{Alki dsl library}
10
+ spec.description = %q{Library for defining and using DSLs}
11
+ spec.homepage = "https://github.com/medlefsen/alki-dsl"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
16
+ spec.bindir = 'exe'
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'alki-support', '~> 0.3'
21
+ spec.add_development_dependency 'minitest', '~> 5.9', '>= 5.9.1'
22
+ end
@@ -0,0 +1,132 @@
1
+ require 'forwardable'
2
+ require 'alki/support'
3
+
4
+ module Alki
5
+ class ClassBuilder
6
+ def self.create_constant(name,value = Class.new, parent=nil)
7
+ parent ||= Object
8
+ *ans, ln = name.to_s.split('::')
9
+ ans.each do |a|
10
+ unless parent.const_defined? a
11
+ parent.const_set a, Module.new
12
+ end
13
+ parent = parent.const_get a
14
+ end
15
+
16
+ parent.const_set ln, value
17
+ end
18
+
19
+ def self.build(data)
20
+ class_name = data[:class_name]
21
+ if !class_name && data[:name] && data[:prefix]
22
+ class_name = Alki::Support.classify(
23
+ data[:prefix].empty? ? data[:name] : "#{data[:prefix]}/#{data[:name]}"
24
+ )
25
+ end
26
+
27
+ if data[:type] == :module
28
+ klass = Module.new
29
+ else
30
+ super_class = if data[:super_class]
31
+ Alki::Support.load_class data[:super_class]
32
+ else
33
+ Object
34
+ end
35
+ klass = Class.new super_class
36
+ end
37
+ build_class data, klass
38
+ if class_name
39
+ create_constant class_name, klass, data[:parent_class]
40
+ end
41
+ if data[:secondary_classes]
42
+ data[:secondary_classes].each do |data|
43
+ if data[:subclass]
44
+ data = data.merge(parent_class: klass,class_name: data[:subclass])
45
+ elsif !data[:class_name] && !data[:name]
46
+ raise ArgumentError.new("Secondary classes must have names")
47
+ end
48
+ build data
49
+ end
50
+ end
51
+ klass
52
+ end
53
+
54
+ def self.module_not_empty?(mod)
55
+ not mod.instance_methods.empty? &&
56
+ mod.private_instance_methods.empty?
57
+ end
58
+
59
+ def self.build_class(data,klass)
60
+ if data[:module]
61
+ if module_not_empty? data[:module]
62
+ klass.include data[:module]
63
+ end
64
+ if data[:module].const_defined?(:ClassMethods) &&
65
+ module_not_empty?(data[:module]::ClassMethods)
66
+ klass.extend data[:module]::ClassMethods
67
+ end
68
+ end
69
+
70
+ if data[:modules]
71
+ data[:modules].each do |mod|
72
+ klass.include mod
73
+ end
74
+ end
75
+ if data[:class_modules]
76
+ data[:class_modules].each do |mod|
77
+ klass.extend mod
78
+ end
79
+ end
80
+
81
+ add_methods klass, data
82
+ add_initialize klass, data[:initialize_params] if data[:initialize_params]
83
+ end
84
+
85
+ def self.add_methods(klass, data)
86
+ if data[:class_methods]
87
+ data[:class_methods].each do |name, method|
88
+ klass.define_singleton_method name, &method[:body]
89
+ klass.singleton_class.send :private, name if method[:private]
90
+ end
91
+ end
92
+
93
+ if data[:instance_methods]
94
+ data[:instance_methods].each do |name, method|
95
+ klass.send :define_method, name, &method[:body]
96
+ klass.send :private, name if method[:private]
97
+ end
98
+ end
99
+
100
+ if data[:delegators]
101
+ klass.extend Forwardable
102
+ data[:delegators].each do |name,delegator|
103
+ klass.def_delegator delegator[:accessor], delegator[:method], name
104
+ end
105
+ end
106
+
107
+ klass.send :attr_reader, *data[:attr_readers] if data[:attr_readers]
108
+ klass.send :attr_writer, *data[:attr_writers] if data[:attr_writers]
109
+ klass.send :attr_accessor, *data[:attr_accessors] if data[:attr_accessors]
110
+ end
111
+
112
+ def self.add_initialize(klass,params)
113
+ at_setters = ''
114
+ params.each do |(p,default)|
115
+ if default
116
+ default_method = "_default_#{p}".to_sym
117
+ klass.send :define_method, default_method do
118
+ default
119
+ end
120
+ klass.send :private, default_method
121
+ at_setters << "@#{p} = #{p} || #{default_method}\n"
122
+ else
123
+ at_setters << "@#{p} = #{p}\n"
124
+ end
125
+ end
126
+
127
+ klass.class_eval "
128
+ def initialize(#{params.map{|p| p[1] ? "#{p[0]}=nil" : p[0]}.join(', ')})
129
+ #{at_setters}end"
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,45 @@
1
+ require 'alki/support'
2
+ require 'alki/dsl/evaluator'
3
+
4
+ module Alki
5
+ module Dsl
6
+ class Base
7
+ def self.build(data={},&blk)
8
+ Alki::Dsl::Evaluator.evaluate self, data, &blk
9
+ end
10
+
11
+ def self.generate(ctx)
12
+ obj = new(ctx)
13
+ result = {methods: {}}
14
+ info = self.dsl_info
15
+
16
+ result[:init] = obj.method(info[:init]) if info[:init]
17
+ result[:finish] = obj.method(info[:finish]) if info[:finish]
18
+ result[:requires] = info[:requires] if info[:requires]
19
+ result[:helpers] = info[:helpers] if info[:helpers]
20
+
21
+ if info[:methods]
22
+ info[:methods].each do |method|
23
+ if method.is_a?(Array)
24
+ name, method = method
25
+ else
26
+ name = method
27
+ end
28
+ result[:methods][name] = obj.method method
29
+ end
30
+ end
31
+ result
32
+ end
33
+
34
+ def self.dsl_info
35
+ {}
36
+ end
37
+
38
+ def initialize(ctx)
39
+ @ctx = ctx
40
+ end
41
+
42
+ attr_reader :ctx
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+ require 'alki/support'
2
+ require 'alki/dsl/evaluator'
3
+
4
+ module Alki
5
+ module Dsl
6
+ class Builder
7
+ def self.build(data,&blk)
8
+ result = Alki::Dsl::Evaluator.evaluate _dsls,data,&blk
9
+ if _processor
10
+ _processor.build result
11
+ else
12
+ result
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def self.dsl(name)
19
+ klass = Alki::Support.load_class name
20
+ unless klass
21
+ raise "Unable to load class #{name.inspect}"
22
+ end
23
+ dsls = _dsls
24
+ dsls += [klass]
25
+ define_singleton_method(:_dsls) { dsls }
26
+ end
27
+
28
+ def self.processor(name)
29
+ klass = Alki::Support.load_class name
30
+ define_singleton_method(:_processor) { klass }
31
+ end
32
+
33
+ def self._dsls
34
+ []
35
+ end
36
+
37
+ def self._processor
38
+ nil
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,86 @@
1
+ module Alki
2
+ module Dsl
3
+ module ClassHelpers
4
+ def class_builder(subclass = nil)
5
+ unless @ctx[:class_builder]
6
+ @ctx[:class_builder] = {}
7
+ %i(module name prefix).each do |attr|
8
+ @ctx[:class_builder][attr] = @ctx[attr] if @ctx[attr]
9
+ end
10
+ end
11
+ if subclass
12
+ scs = @ctx[:class_builder][:secondary_classes] ||= []
13
+ cb = scs.find { |sc| sc[:subclass] == subclass }
14
+ unless cb
15
+ cb = { subclass: subclass }
16
+ scs << cb
17
+ end
18
+ cb
19
+ else
20
+ @ctx[:class_builder]
21
+ end
22
+ end
23
+
24
+ def create_as_module(subclass: nil)
25
+ class_builder(subclass)[:type] = :module
26
+ end
27
+
28
+ def set_super_class(klass,subclass: nil)
29
+ class_builder(subclass)[:super_class] = klass
30
+ end
31
+
32
+ def add_method(name,context:nil,private: false,subclass: nil, &blk)
33
+ class_builder(subclass)[:instance_methods] ||= {}
34
+ class_builder(subclass)[:instance_methods][name.to_sym] = {
35
+ body: blk,
36
+ context: context,
37
+ private: private
38
+ }
39
+ end
40
+
41
+ def add_class_method (name,context: nil,private: false,subclass: nil,&blk)
42
+ class_builder(subclass)[:class_methods] ||= {}
43
+ class_builder(subclass)[:class_methods][name.to_sym] = {
44
+ body: blk,
45
+ context: context,
46
+ private: private
47
+ }
48
+ end
49
+
50
+ def add_helper(name,&blk)
51
+ class_builder('Helpers')[:type] = :module
52
+ add_method name, &blk
53
+ add_method name, subclass: 'Helpers', &blk
54
+ end
55
+
56
+ def add_helper_module(mod)
57
+ class_builder('Helpers')[:type] = :module
58
+ add_module mod
59
+ add_module mod, subclass: 'Helpers'
60
+ end
61
+
62
+ def add_initialize_param(name,default=nil,subclass: nil)
63
+ (class_builder(subclass)[:initialize_params]||=[]) << [name.to_sym,default]
64
+ end
65
+
66
+ def add_instance_class_proxy(type, name,subclass: nil)
67
+ (class_builder(subclass)[:instance_class]||={})[name.to_sym] = {type: type}
68
+ end
69
+
70
+ def add_module(mod,subclass: nil)
71
+ (class_builder(subclass)[:modules]||=[]) << mod
72
+ end
73
+
74
+ def add_accessor(name,type: :accessor,subclass: nil)
75
+ (class_builder(subclass)["attr_#{type}s".to_sym]||=[]) << name
76
+ end
77
+
78
+ def add_delegator(name,accessor,method=name,subclass: nil)
79
+ (class_builder(subclass)[:delegators]||={})[name] = {
80
+ accessor: accessor,
81
+ method: method
82
+ }
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,67 @@
1
+ require 'set'
2
+ require 'alki/support'
3
+
4
+ module Alki
5
+ module Dsl
6
+ class Evaluator
7
+ def initialize
8
+ @inits = []
9
+ @finishers = []
10
+ @processors = []
11
+ @dsls_seen = Set.new
12
+ end
13
+
14
+ def evaluate(dsl,data={},&blk)
15
+ mod = (data[:module] ||= Module.new)
16
+ process_dsl dsl, data
17
+
18
+ @inits.each(&:call)
19
+ dsl_exec mod, &blk
20
+ @finishers.reverse_each(&:call)
21
+ clear_dsl_methods mod
22
+
23
+ @processors.each do |processor|
24
+ processor.build data
25
+ end
26
+
27
+ data
28
+ end
29
+
30
+ def process_dsl(dsl,data)
31
+ return unless @dsls_seen.add? dsl
32
+ cbs = dsl.generate(data)
33
+ if cbs[:requires]
34
+ cbs[:requires].each do |required_dsl|
35
+ process_dsl Alki::Support.load_class(required_dsl), data
36
+ end
37
+ end
38
+ @inits << cbs[:init] if cbs[:init]
39
+ @finishers << cbs[:finish] if cbs[:finish]
40
+ @processors << cbs[:processors] if cbs[:processors]
41
+ if cbs[:methods]
42
+ cbs[:methods].each do |name, proc|
43
+ define_dsl_method data[:module], name, &proc
44
+ end
45
+ end
46
+ end
47
+
48
+ def define_dsl_method(mod,name,&blk)
49
+ mod.define_singleton_method name, &blk
50
+ end
51
+
52
+ def clear_dsl_methods(mod)
53
+ mod.singleton_methods do |m|
54
+ mod.singleton_class.send :remove_method, m
55
+ end
56
+ end
57
+
58
+ def dsl_exec(mod,&blk)
59
+ mod.class_exec &blk
60
+ end
61
+
62
+ def self.evaluate(dsl, data={}, &blk)
63
+ new.evaluate dsl, data, &blk
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,28 @@
1
+ require 'alki/support'
2
+ require 'alki/dsl'
3
+
4
+ module Alki
5
+ module Dsl
6
+ class Loader
7
+ def initialize(root_dir)
8
+ @root_dir = root_dir
9
+ end
10
+
11
+ def all_paths
12
+ Dir[File.join(@root_dir,'**','*.rb')].map do |path|
13
+ path.gsub(File.join(@root_dir,''),'').gsub(/\.rb$/,'')
14
+ end
15
+ end
16
+
17
+ def load_all
18
+ all_paths.inject({}) do |h,path|
19
+ h.merge!(path => Alki::Dsl.load(path))
20
+ end
21
+ end
22
+
23
+ def load(file)
24
+ Alki::Dsl.load File.expand_path("#{file}.rb",@root_dir)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ require 'alki/dsl/loader'
2
+ require 'alki/support'
3
+
4
+ module Alki
5
+ module Dsl
6
+ module Registry
7
+ @registered_paths = {}
8
+ @registered_dirs = {}
9
+
10
+ def self.register(path,builder,**data)
11
+ @registered_paths[File.absolute_path(path)] = Entry.new(builder,data)
12
+ end
13
+
14
+ def self.register_dir(dir_path,builder,**data)
15
+ @registered_dirs[File.join(File.absolute_path(dir_path),'')] = [builder,data]
16
+ end
17
+
18
+ def self.lookup(path, load_configs: true)
19
+ path = File.absolute_path path
20
+ entry = @registered_paths[path]
21
+ return entry if entry
22
+
23
+ @registered_dirs.each do |dir,(builder,data)|
24
+ if path.start_with? dir
25
+ data = {name: Alki::Support.path_name(path, dir)}.merge data
26
+ return Entry.new(builder,data)
27
+ end
28
+ end
29
+
30
+ if load_configs
31
+ root = Alki::Support.find_root(path) do |dir|
32
+ File.exists?(File.join(dir,'config','dsls.rb'))
33
+ end
34
+ if root
35
+ config_file = File.join(root,'config','dsls.rb')
36
+ register config_file, 'alki/dsls/dsl_config', root: root
37
+ require config_file
38
+ return lookup path, load_configs: false
39
+ end
40
+ end
41
+
42
+ nil
43
+ end
44
+
45
+ def self.build(path,&blk)
46
+ entry = lookup path
47
+ if entry
48
+ entry.build blk
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
54
+ class Entry
55
+ def initialize(builder,data)
56
+ @builder = builder
57
+ @data = data
58
+ end
59
+
60
+ def build(blk)
61
+ Alki::Support.load_class(@builder).build @data, &blk
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,5 @@
1
+ module Alki
2
+ module Dsl
3
+ VERSION = '0.3.0'
4
+ end
5
+ end
data/lib/alki/dsl.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'alki/dsl/evaluator'
2
+ require 'alki/dsl/registry'
3
+
4
+ module Alki
5
+ module Dsl
6
+ @loaded = {}
7
+ def self.[]=(path,value)
8
+ @loaded[path] =value
9
+ end
10
+
11
+ def self.[](path)
12
+ @loaded[path]
13
+ end
14
+
15
+ def self.register(*args)
16
+ Alki::Dsl::Registry.register *args
17
+ end
18
+
19
+ def self.register_dir(*args)
20
+ Alki::Dsl::Registry.register_dir *args
21
+ end
22
+
23
+ def self.load(path)
24
+ path = File.absolute_path(path)
25
+ require path
26
+ self[path]
27
+ end
28
+
29
+ def self.build(name,data={},&blk)
30
+ Alki::Support.load_class(name).build data, &blk
31
+ end
32
+ end
33
+ end
34
+
35
+ module Kernel
36
+ def Alki(builder=nil,&blk)
37
+ if blk
38
+ path = caller_locations(1,1)[0].absolute_path
39
+ result = if builder
40
+ builder.build({}, &blk)
41
+ else
42
+ Alki::Dsl::Registry.build path, &blk
43
+ end
44
+ Alki::Dsl[path] = result
45
+ end
46
+ ::Alki
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ require 'alki/dsl/base'
2
+ require 'alki/dsl/class_helpers'
3
+ require 'alki/class_builder'
4
+
5
+ module Alki
6
+ module Dsls
7
+ class Class < Alki::Dsl::Base
8
+ include Alki::Dsl::ClassHelpers
9
+
10
+ self::Helpers = Alki::Dsl::ClassHelpers
11
+
12
+ def self.dsl_info
13
+ {
14
+ methods: %i(class_methods),
15
+ finish: :finish
16
+ }
17
+ end
18
+
19
+ def class_methods(&blk)
20
+ unless ctx[:module].const_defined? :ClassMethods
21
+ ctx[:module].const_set :ClassMethods, Module.new
22
+ end
23
+ ctx[:module]::ClassMethods.class_exec &blk
24
+ end
25
+
26
+ def finish
27
+ ctx[:class] = Alki::ClassBuilder.build class_builder
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,78 @@
1
+ require 'alki/dsl/base'
2
+ require 'alki/support'
3
+ require 'alki/dsl/class_helpers'
4
+
5
+ module Alki
6
+ module Dsls
7
+ class Dsl < Alki::Dsl::Base
8
+ include Alki::Dsl::ClassHelpers
9
+ Helpers = Alki::Dsl::ClassHelpers
10
+
11
+ def self.dsl_info
12
+ {
13
+ requires: ['alki/dsls/class'],
14
+ methods: [
15
+ :dsl_method,
16
+ [:init,:dsl_init],
17
+ [:finish,:dsl_finish],
18
+ :require_dsl,
19
+ :helper,
20
+ :helper_module
21
+ ],
22
+ init: :init,
23
+ finish: :finish
24
+ }
25
+ end
26
+
27
+ def init
28
+ @info = {
29
+ methods: [],
30
+ requires: []
31
+ }
32
+ @helper_modules = []
33
+ @helpers = {}
34
+ end
35
+
36
+ def dsl_method(name, &blk)
37
+ method_name = name.to_sym
38
+ add_method method_name, private: true, &blk
39
+ @info[:methods] << [name.to_sym,method_name]
40
+ end
41
+
42
+ def dsl_init(&blk)
43
+ add_method :_dsl_init, private: true, &blk
44
+ @info[:init] = :_dsl_init
45
+ end
46
+
47
+ def dsl_finish(&blk)
48
+ add_method :_dsl_finish, private: true, &blk
49
+ @info[:finish] = :_dsl_finish
50
+ end
51
+
52
+ def require_dsl(dsl)
53
+ dsl_class = Alki::Support.load_class(dsl)
54
+ @info[:requires] << dsl_class
55
+ if defined? dsl_class::Helpers
56
+ add_module dsl_class::Helpers
57
+ add_helper_module dsl_class::Helpers
58
+ end
59
+ end
60
+
61
+ def helper(name,&blk)
62
+ add_helper name, &blk
63
+ end
64
+
65
+ def helper_module(mod)
66
+ add_helper_module mod
67
+ end
68
+
69
+ def finish
70
+ set_super_class 'alki/dsl/base'
71
+ info = @info.freeze
72
+ add_class_method :dsl_info do
73
+ info
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,28 @@
1
+ require 'alki/dsl/base'
2
+
3
+ module Alki
4
+ module Dsls
5
+ class DslConfig < Alki::Dsl::Base
6
+ def self.dsl_info
7
+ {
8
+ methods: %i(register register_dir register_lib_dir)
9
+ }
10
+ end
11
+
12
+ def register(path,*args)
13
+ path = File.expand_path(path,@ctx[:root])
14
+ Alki::Dsl::Registry.register path, *args
15
+ end
16
+
17
+ def register_dir(path,*args)
18
+ path = File.expand_path(path,@ctx[:root])
19
+ Alki::Dsl::Registry.register_dir path, *args
20
+ end
21
+
22
+ def register_lib_dir(prefix,dsl,**data)
23
+ path = File.join(@ctx[:root],'lib', prefix)
24
+ Alki::Dsl::Registry.register_dir path, dsl, data.merge(prefix: prefix)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ require_relative '../test_helper'
2
+ require 'alki/dsl'
3
+
4
+ describe 'dsl configuration' do
5
+ before do
6
+ $LOAD_PATH.unshift fixture_path('example','lib')
7
+ end
8
+
9
+ it 'should be automatically loaded when requiring a dsl' do
10
+ require 'alki_test/dsls/number'
11
+ AlkiTest::Dsls::Number.must_be_instance_of Class
12
+ AlkiTest::Dsls::Number.singleton_methods.must_include :generate
13
+ end
14
+
15
+ it 'should allow using dsls specified in same dsl config' do
16
+ Kernel.load(fixture_path('example','numbers','three.rb'))
17
+ AlkiTest::Numbers::Three.new.must_equal 3
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ Alki do
2
+ register_dir 'numbers', 'alki_test/dsls/number', prefix: 'alki_test/numbers'
3
+ register_lib_dir 'alki_test/dsls', 'alki/dsls/dsl'
4
+ end
@@ -0,0 +1,11 @@
1
+ Alki do
2
+ require_dsl 'alki_test/dsls/value'
3
+
4
+ init do
5
+ self.value = 0
6
+ end
7
+
8
+ dsl_method :succ do
9
+ self.value += 1
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ Alki do
2
+ require_dsl 'alki/dsls/class'
3
+
4
+ helper :value= do |v|
5
+ ctx[:value] = v
6
+ end
7
+
8
+ helper :value do
9
+ ctx[:value]
10
+ end
11
+
12
+ finish do
13
+ create_as_module
14
+ value = ctx[:value]
15
+ add_class_method :new do
16
+ value
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ Alki do
2
+ succ
3
+ succ
4
+ succ
5
+ end
@@ -0,0 +1,148 @@
1
+ require_relative '../test_helper'
2
+ require 'alki/class_builder'
3
+
4
+ describe Alki::ClassBuilder do
5
+ describe :build do
6
+ def build(data={})
7
+ Alki::ClassBuilder.build data
8
+ end
9
+
10
+ it 'should create and return a new class' do
11
+ build.must_be_instance_of Class
12
+ end
13
+
14
+ it 'should allow creation of modules' do
15
+ build(type: :module).must_be_instance_of Module
16
+ end
17
+
18
+ it 'should allow setting instance methods' do
19
+ obj = build(
20
+ instance_methods: {
21
+ test1: {
22
+ body: -> { :test1 }
23
+ },
24
+ test2: {
25
+ body: -> { :test2 },
26
+ private: true
27
+ }
28
+ }
29
+ ).new
30
+ obj.test1.must_equal :test1
31
+ assert_raises NoMethodError do
32
+ obj.test2
33
+ end
34
+ obj.send(:test2).must_equal :test2
35
+ end
36
+
37
+ it 'should allow setting class methods' do
38
+ klass = build(
39
+ class_methods: {
40
+ test1: {
41
+ body: -> { :test1 }
42
+ },
43
+ test2: {
44
+ body: -> { :test2 },
45
+ private: true
46
+ }
47
+ }
48
+ )
49
+ klass.test1.must_equal :test1
50
+ assert_raises NoMethodError do
51
+ klass.test2
52
+ end
53
+ klass.send(:test2).must_equal :test2
54
+ end
55
+
56
+ it 'should allow setting super class' do
57
+ super_class = Class.new
58
+ build(super_class: super_class).superclass.must_equal super_class
59
+ end
60
+
61
+ it 'should allow setting super class by name' do
62
+ class AlkiTestClass; end
63
+ build(super_class: 'alki_test_class').superclass.must_equal AlkiTestClass
64
+ Object.send :remove_const, :AlkiTestClass
65
+ end
66
+
67
+ it 'should include module and extend module::ClassMethods if provided' do
68
+ m = Module.new do
69
+ module self::ClassMethods
70
+ def test1
71
+ :test1
72
+ end
73
+ end
74
+ def test2
75
+ :test2
76
+ end
77
+ end
78
+ klass = build(module: m)
79
+ klass.included_modules.must_include m
80
+ klass.test1.must_equal :test1
81
+ klass.new.test2.must_equal :test2
82
+ end
83
+
84
+ it 'should include modules' do
85
+ ms = [Module.new,Module.new]
86
+ klass = build(modules: ms)
87
+ ms.each do |m|
88
+ klass.included_modules.must_include m
89
+ end
90
+ end
91
+
92
+ it 'should extend class_modules' do
93
+ ms = [
94
+ Module.new { def test1; :test1; end },
95
+ Module.new { def test2; :test2; end },
96
+ ]
97
+ klass = build(class_modules: ms)
98
+ klass.test1.must_equal :test1
99
+ klass.test2.must_equal :test2
100
+ end
101
+
102
+ it 'should create basic #initialize using initialize_params' do
103
+ obj = build(initialize_params: [:a,:b]).new 1, 2
104
+ obj.instance_variable_get(:@a).must_equal 1
105
+ obj.instance_variable_get(:@b).must_equal 2
106
+ end
107
+
108
+ it 'should allow providing a class name' do
109
+ if defined?(AlkiTestClass)
110
+ Object.send :remove_const, :AlkiTestClass
111
+ end
112
+ build(class_name: "AlkiTestClass")
113
+ assert(defined?(AlkiTestClass),'Expected AlkiTestClass to be defined')
114
+ Object.send :remove_const, :AlkiTestClass
115
+ assert(!defined?(AlkiTestClass))
116
+ end
117
+
118
+ it 'should use name to create class name' do
119
+ if defined?(AlkiTest::TestClass)
120
+ Object.send :remove_const, :AlkiTest
121
+ end
122
+ build(prefix: '', name: "alki_test/test_class")
123
+ assert(defined?(AlkiTest::TestClass),'Expected AlkiTest::TestClass to be defined')
124
+ Object.send :remove_const, :AlkiTest
125
+ end
126
+
127
+ it 'should use prefix and name to create class name' do
128
+ if defined?(AlkiTest::TestClass)
129
+ Object.send :remove_const, :AlkiTest
130
+ end
131
+ build(prefix: 'alki_test', name: "test_class")
132
+ assert(defined?(AlkiTest::TestClass),'Expected AlkiTest::TestClass to be defined')
133
+ Object.send :remove_const, :AlkiTest
134
+ end
135
+
136
+ it 'should allow creating secondary classes' do
137
+ build(
138
+ secondary_classes: [
139
+ {
140
+ class_name: 'AlkiTestClass'
141
+ }
142
+ ]
143
+ )
144
+ assert(defined?(AlkiTestClass),'Expected AlkiTestClass to be defined')
145
+ Object.send :remove_const, :AlkiTestClass
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib',__FILE__)
2
+
3
+ require 'minitest/autorun'
4
+
5
+ class Minitest::Spec
6
+ def root
7
+ File.expand_path('../..',__FILE__)
8
+ end
9
+
10
+ def fixture_path(*path)
11
+ File.join(root,'test','fixtures',*path)
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ require_relative '../test_helper'
2
+ require 'alki/dsl/evaluator'
3
+
4
+ describe Alki::Dsl::Evaluator do
5
+
6
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alki-dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Matt Edlefsen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: alki-support
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.9'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 5.9.1
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '5.9'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 5.9.1
47
+ description: Library for defining and using DSLs
48
+ email:
49
+ - matt.edlefsen@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - ".gitignore"
55
+ - Gemfile
56
+ - alki-dsl.gemspec
57
+ - lib/alki/class_builder.rb
58
+ - lib/alki/dsl.rb
59
+ - lib/alki/dsl/base.rb
60
+ - lib/alki/dsl/builder.rb
61
+ - lib/alki/dsl/class_helpers.rb
62
+ - lib/alki/dsl/evaluator.rb
63
+ - lib/alki/dsl/loader.rb
64
+ - lib/alki/dsl/registry.rb
65
+ - lib/alki/dsl/version.rb
66
+ - lib/alki/dsls/class.rb
67
+ - lib/alki/dsls/dsl.rb
68
+ - lib/alki/dsls/dsl_config.rb
69
+ - test/feature/config_test.rb
70
+ - test/fixtures/example/config/dsls.rb
71
+ - test/fixtures/example/lib/alki_test/dsls/number.rb
72
+ - test/fixtures/example/lib/alki_test/dsls/value.rb
73
+ - test/fixtures/example/numbers/three.rb
74
+ - test/integration/class_builder_test.rb
75
+ - test/test_helper.rb
76
+ - test/unit/evaluator_test.rb
77
+ homepage: https://github.com/medlefsen/alki-dsl
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.5.1
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Alki dsl library
101
+ test_files:
102
+ - test/feature/config_test.rb
103
+ - test/fixtures/example/config/dsls.rb
104
+ - test/fixtures/example/lib/alki_test/dsls/number.rb
105
+ - test/fixtures/example/lib/alki_test/dsls/value.rb
106
+ - test/fixtures/example/numbers/three.rb
107
+ - test/integration/class_builder_test.rb
108
+ - test/test_helper.rb
109
+ - test/unit/evaluator_test.rb