dsl 0.1.0
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.
- data/.gitignore +1 -0
- data/README.md +49 -0
- data/VERSION +1 -0
- data/dsl.rb +34 -0
- data/examples/database.rb +77 -0
- data/examples/user.rb +25 -0
- data/examples/webapp.rb +43 -0
- metadata +75 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Rakefile
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# DSL
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
dsl.rb is a small script (26 lines) to help create domain specific languages within Ruby.
|
6
|
+
|
7
|
+
## Install
|
8
|
+
|
9
|
+
Until I setup the gem... just clone and play around with it.
|
10
|
+
|
11
|
+
## Quick Example
|
12
|
+
|
13
|
+
require 'dsl'
|
14
|
+
|
15
|
+
class UserDSL < DSL
|
16
|
+
def name(n); @name = n; end
|
17
|
+
def gender(g); @gender = g; end
|
18
|
+
def age(a); @age = a; end
|
19
|
+
end
|
20
|
+
|
21
|
+
class User
|
22
|
+
attr :name, :gender, :age
|
23
|
+
dsl_method :edit => UserDSL
|
24
|
+
end
|
25
|
+
|
26
|
+
ryguy = User.new
|
27
|
+
|
28
|
+
ryguy.edit do
|
29
|
+
name 'Ryan Lewis'
|
30
|
+
gender :male
|
31
|
+
age 19
|
32
|
+
end
|
33
|
+
|
34
|
+
p ryguy
|
35
|
+
# => #<User:0x00000001b6dc78 @name="Ryan Lewis", @gender=:male, @age=19>
|
36
|
+
|
37
|
+
As you can see, simply requiring DSL adds the Module/Class method `dsl_method`, which defines a new instance method for your class that only accepts a block.
|
38
|
+
|
39
|
+
`dsl_method` only accepts a `Hash`, the key being the instance method name and the value being the DSL class the method will use.
|
40
|
+
|
41
|
+
When your DSL instance method is called (with a block, of course), all of your object's instance variables are delegated into a new instance of the DSL class assigned to the called DSL instance method.
|
42
|
+
The block is then `instance_eval`'d within the new DSL class instance where you can use the instance variables.
|
43
|
+
When the block is closed, all of the instance variables are then transfered back to your object.
|
44
|
+
|
45
|
+
Therefor, creating a Domain Specific Language is as easy as subclassing the `DSL` class. That's it!
|
46
|
+
|
47
|
+
## Copyright
|
48
|
+
|
49
|
+
Copyright (c) 2010 Ryan Lewis. See LICENSE for details.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/dsl.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class DSL
|
4
|
+
def self.call(parent, &blk)
|
5
|
+
instance = new
|
6
|
+
# Add all of the parents instance variables to the instance
|
7
|
+
parent.instance_variables.each do |instance_variable|
|
8
|
+
value = parent.instance_variable_get(instance_variable)
|
9
|
+
instance.instance_variable_set(instance_variable, value)
|
10
|
+
end
|
11
|
+
# Instance eval the block in the instance
|
12
|
+
instance.instance_eval(&blk)
|
13
|
+
# Replace all of the parents instance variables with the instance's
|
14
|
+
instance.instance_variables.each do |instance_variable|
|
15
|
+
value = instance.instance_variable_get(instance_variable)
|
16
|
+
parent.instance_variable_set(instance_variable, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Module
|
22
|
+
def dsl_method(opts)
|
23
|
+
# Complain if the argument isn't a hash
|
24
|
+
raise(TypeError) unless opts.is_a?(Hash)
|
25
|
+
# For each dsl_method, define it in the class
|
26
|
+
# The methods do not accept arguments, only blocks
|
27
|
+
opts.each do |method, dsl_class|
|
28
|
+
define_method(method) do |&blk|
|
29
|
+
raise(ArgumentError, "method #{method} requires a block") unless block_given?
|
30
|
+
dsl_class.call(self, &blk)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'dsl')
|
4
|
+
|
5
|
+
class Database
|
6
|
+
class Table
|
7
|
+
def initialize
|
8
|
+
@schema = {}
|
9
|
+
@entries = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(opts)
|
13
|
+
raise(TypeError) unless opts.is_a?(Hash)
|
14
|
+
opts.each do |name, v|
|
15
|
+
raise("key '#{name}' not defined in schema") unless @schema.has_key?(name)
|
16
|
+
if @schema[name] == :primary_key
|
17
|
+
raise('You cannot set primary keys')
|
18
|
+
else
|
19
|
+
raise("key '#{name}' not of type #{@schema[name]}") unless v.is_a?(@schema[name])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@schema.select { |name, v| v == :primary_key }.each do |name, v|
|
23
|
+
opts[name] = @entries.count
|
24
|
+
end
|
25
|
+
@entries << opts
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](id)
|
29
|
+
@entries.find_all do |entry|
|
30
|
+
entry[:id] == id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class SchemaDSL < DSL
|
36
|
+
def primary_key(name); @schema[name] = :primary_key; end
|
37
|
+
def String(name); @schema[name] = ::String; end
|
38
|
+
def Integer(name); @schema[name] = ::Integer; end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@tables = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def table(name, &blk)
|
46
|
+
if block_given?
|
47
|
+
raise("Table '#{name}' already exists") unless @tables[name].nil?
|
48
|
+
@tables[name] = Table.new
|
49
|
+
SchemaDSL.call(@tables[name], &blk)
|
50
|
+
else
|
51
|
+
@tables[name]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
require 'ap'
|
57
|
+
|
58
|
+
db = Database.new
|
59
|
+
|
60
|
+
db.table(:users) do
|
61
|
+
primary_key :id
|
62
|
+
String :username
|
63
|
+
Integer :age
|
64
|
+
end
|
65
|
+
|
66
|
+
db.table(:users).create(:username => 'Foo', :age => 19)
|
67
|
+
db.table(:users).create(:username => 'Bar', :age => 43)
|
68
|
+
|
69
|
+
p db.table(:users)[0]
|
70
|
+
# => [{:username=>"Foo", :age=>19, :id=>0}]
|
71
|
+
|
72
|
+
p db.table(:users)[1]
|
73
|
+
# => [{:username=>"Bar", :age=>43, :id=>1}]
|
74
|
+
|
75
|
+
db.table(:users).create(:username => 'Baz', :age => 'One Hundred')
|
76
|
+
# => ERROR: key 'age' not of type Integer (RuntimeError)
|
77
|
+
|
data/examples/user.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'dsl')
|
4
|
+
|
5
|
+
class UserDSL < DSL
|
6
|
+
def name(n); @name = n; end
|
7
|
+
def gender(g); @gender = g; end
|
8
|
+
def age(a); @age = a; end
|
9
|
+
end
|
10
|
+
|
11
|
+
class User
|
12
|
+
attr :name, :gender, :age
|
13
|
+
dsl_method :edit => UserDSL
|
14
|
+
end
|
15
|
+
|
16
|
+
ryguy = User.new
|
17
|
+
|
18
|
+
ryguy.edit do
|
19
|
+
name 'Ryan Lewis'
|
20
|
+
gender :male
|
21
|
+
age 19
|
22
|
+
end
|
23
|
+
|
24
|
+
p ryguy
|
25
|
+
# => #<User:0x00000001b6dc78 @name="Ryan Lewis", @gender=:male, @age=19>
|
data/examples/webapp.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'dsl')
|
4
|
+
|
5
|
+
class ConfigDSL < DSL
|
6
|
+
def add_helpers(*h)
|
7
|
+
@helpers.concat(h)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class WebApp
|
12
|
+
attr :helpers
|
13
|
+
dsl_method :config => ConfigDSL
|
14
|
+
|
15
|
+
#===--- OR:
|
16
|
+
# dsl_method :config => Class.new(DSL) {
|
17
|
+
# def add_helpers(*h)
|
18
|
+
# @helpers.concat(h)
|
19
|
+
# end
|
20
|
+
# }
|
21
|
+
|
22
|
+
#===--- MAYBE:
|
23
|
+
# define_dsl_method :config do
|
24
|
+
# def add_helpers; end
|
25
|
+
# end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@helpers = ['helpers/foo', 'helpers/bar']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
web_app = WebApp.new
|
33
|
+
|
34
|
+
p web_app.helpers
|
35
|
+
# => ["helpers/foo", "helpers/bar"]
|
36
|
+
|
37
|
+
web_app.config do
|
38
|
+
add_helpers 'helpers/baz', 'helpers/qux'
|
39
|
+
end
|
40
|
+
|
41
|
+
p web_app.helpers
|
42
|
+
# => ["helpers/foo", "helpers/bar", "helpers/baz", "helpers/qux"]
|
43
|
+
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dsl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ryan Lewis
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-16 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Easily create Domain Specific Languages with any block. You can also link instance methods to your DSL.
|
23
|
+
email: c00lryguy@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.md
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- README.md
|
33
|
+
- VERSION
|
34
|
+
- dsl.rb
|
35
|
+
- examples/database.rb
|
36
|
+
- examples/user.rb
|
37
|
+
- examples/webapp.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/c00lryguy/dsl
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
hash: 3
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.7
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A small library for creating Domain Specific Languages (DSLs)
|
72
|
+
test_files:
|
73
|
+
- examples/webapp.rb
|
74
|
+
- examples/database.rb
|
75
|
+
- examples/user.rb
|