aster 0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 58243f4638f7370eaedd71419622f967f24bd60e
4
+ data.tar.gz: 8426cc93373842fb7cf66d2fcc3c389a47cdecf1
5
+ SHA512:
6
+ metadata.gz: 1adc2b41461422e04081c6fa8c4d9f2c460b8661691ee0aff87bacf5fc7d9b611fa031a7e1115b680221e767f071ec0c61ca953d44761e2062191fbb863a7ae4
7
+ data.tar.gz: 1cdcbe16dff0aaf31ec201df89181461416f94d3c1044d890de17ad664b60c8a06fcf7f8b6622266cc051f950fe647b2d3172770a2d3e3e7b3439b194bcd65ef
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in aster.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sam Murphy
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Aster
2
+
3
+ Aster is a programming language that's designed to make configuration management more fun.
4
+
5
+ ## Example
6
+
7
+ server web
8
+ default-instance-vars
9
+ var username root
10
+ var ssh-port 22
11
+
12
+ configure
13
+ run upgrade-ubuntu.sh
14
+ exec sudo reboot
15
+ exec sudo apt-get install nginx
16
+ run create-admin-user.aster
17
+ config-set username admin
18
+ config-set ssh-port 2222
19
+ upload sample.conf /etc/conf
20
+
21
+ add-remote-file-runner .rb
22
+ exec `which ruby`
23
+
24
+ file hostname.rb
25
+ require 'rubygems'
26
+ puts `hostname`.strip
27
+
28
+ file database.yml
29
+ ---
30
+ production:
31
+ adapter: mysql2
32
+ username: root
33
+ password: 00000000
34
+
35
+ file sample.conf xml
36
+ <xml>
37
+ <var val="test" />
38
+ </xml>
39
+
40
+ function hostname
41
+ exec-script hostname.ruby
42
+
43
+ create-server-instance web
44
+ configure-instance {{instance.id}}
45
+
46
+ ## Install
47
+
48
+ gem install aster
49
+
50
+ ## Usage
51
+
52
+ Aster is not a configuration management application. Right now it is an experimental language that supports other languages embedded within `.aster` files.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+
4
+ task :default => :test
5
+
6
+ require 'rake/testtask'
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << 'lib' << 'test' << '.'
9
+ test.pattern = 'test/**/test_*.rb'
10
+ test.verbose = true
11
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ # TODO
2
+
3
+ * reserve gem name
4
+ * eval sub-commands like "equal {add 1 1} 2"
data/aster.gemspec ADDED
@@ -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 'aster/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "aster"
8
+ spec.version = Aster::VERSION
9
+ spec.authors = ["Sam Murphy"]
10
+ spec.email = ["sam.murphy@gmail.com"]
11
+ spec.summary = %q{A programming language for configuring servers}
12
+ #spec.description = %q{TODO: Write a longer description. Optional.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "treetop"
22
+ #spec.add_dependency "thor"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "pry"
27
+ end
data/lib/aster.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "aster/version"
2
+
3
+ module Aster
4
+ # Your code goes here...
5
+ end
6
+
7
+ require 'pry'
8
+
9
+ require_relative './aster/version'
10
+ require_relative './aster/variable'
11
+ require_relative './aster/command'
12
+ require_relative './aster/environment'
13
+ require_relative './aster/function'
14
+ require_relative './aster/parser'
15
+
@@ -0,0 +1,24 @@
1
+ module Aster
2
+ class Command
3
+ attr_accessor :text, :sublines
4
+
5
+ def initialize(commands, sublines = [])
6
+ @commands = commands
7
+ @sublines = sublines
8
+ end
9
+
10
+ def rest
11
+ @text.split(' ', 2)[1]
12
+ end
13
+
14
+ def arguments
15
+ _, *args = @commands
16
+ args
17
+ end
18
+
19
+ def function_name
20
+ @function_name ||= @commands.first.to_sym
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,114 @@
1
+ module Aster
2
+
3
+ class Environment
4
+
5
+ attr_reader :stderr, :stdout
6
+
7
+ def initialize(parent = nil)
8
+ @parent = parent
9
+ @env = {}
10
+ @stdout = ""
11
+ @stderr = ""
12
+
13
+ if parent.nil?
14
+ define_function :echo, [:_list_] do |arguments|
15
+ @stdout << arguments.join(' ')
16
+ end
17
+ define_function :equal, [:a, :b] do |(a, b)|
18
+ a.to_s == b.to_s ? "yes" : "no"
19
+ end
20
+ end
21
+ end
22
+
23
+ def child
24
+ self.class.new(self)
25
+ end
26
+
27
+ def [](k)
28
+ @env[k.to_sym] || @parent && @parent[k.to_sym]
29
+ end
30
+
31
+ def []=(k, v)
32
+ @env[k.to_sym] = v
33
+ end
34
+
35
+ def eval(script)
36
+ tree = Parser.new.parse script
37
+ eval_tree tree
38
+ end
39
+
40
+ def define_function(name, args, commands = nil, &block)
41
+ @env[name.to_sym] = Function.new(args, commands, &block)
42
+ end
43
+
44
+ private
45
+
46
+ def eval_line(command)
47
+ case command.function_name
48
+ when :function
49
+ fun, *args = command.arguments
50
+ self.define_function(
51
+ fun,
52
+ args,
53
+ command.sublines
54
+ )
55
+ when :if
56
+ cond_value = eval_line Command.new(command.rest)
57
+ if is_true?(cond_value)
58
+ eval_tree command.sublines
59
+ end
60
+ when :not
61
+ cond_value = eval_line Command.new(command.rest)
62
+ is_true?(cond_value) ? "no" : "yes"
63
+ else
64
+ function = self[command.function_name]
65
+ if function
66
+ eval_function(function, command.arguments, self.child)
67
+ else
68
+ #binding.pry
69
+ end
70
+ end
71
+ end
72
+
73
+ def is_true?(val)
74
+ val && value.strip == "yes"
75
+ end
76
+
77
+ def eval_tree(tree)
78
+ tree.each do |command|
79
+ eval_line command
80
+ end
81
+ end
82
+
83
+ def eval_function(function, arguments, env)
84
+ # need to eval args
85
+ arguments = arguments.map do |arg|
86
+ if arg.is_a?(Variable)
87
+ env[arg.name]
88
+ else
89
+ arg
90
+ end
91
+ end
92
+
93
+ # bind arguments
94
+ function.arguments.each_with_index do |a, i|
95
+ env[a] = arguments[i]
96
+ end
97
+
98
+ if function.commands
99
+ env.send :eval_tree, function.commands
100
+ elsif function.block
101
+ function.block.call arguments
102
+ else
103
+ raise
104
+ end
105
+
106
+ end
107
+
108
+
109
+ def eval_custom(m, args)
110
+
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,10 @@
1
+ module Aster
2
+ class Function
3
+ attr_reader :arguments, :commands, :block
4
+ def initialize(args, commands, &block)
5
+ @arguments = args
6
+ @commands = commands
7
+ @block = block
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,72 @@
1
+
2
+ require 'treetop'
3
+
4
+ module Aster
5
+
6
+ Treetop.load(File.dirname(__FILE__) + "/sexp.treetop")
7
+
8
+ class Parser
9
+
10
+ def parse(text)
11
+ lines = text.split("\n")
12
+ parse_lines lines
13
+ end
14
+
15
+ private
16
+
17
+ def text_indent(text)
18
+ return -1 if text.nil?
19
+ white_space = text.match(/^( +)/)
20
+ return 0 if white_space.nil?
21
+ size = white_space[0].size
22
+ size % 2 == 0 ? size / 2 : -1
23
+ end
24
+
25
+ def raw_parse_line(line)
26
+ @sexp ||= SexpParser.new
27
+ result = @sexp.parse(line)
28
+ result.value
29
+ end
30
+
31
+ def parse_line(line)
32
+ Command.new raw_parse_line(line)
33
+ end
34
+
35
+ def parse_lines(lines)
36
+ current_indent = (lines.first ? text_indent(lines.first) : 0)
37
+ last_line = nil
38
+ data = []
39
+ lines.each_with_index do |line, i|
40
+ # Skip Empty lines
41
+ next if line.strip.empty?
42
+
43
+ # Skip Comments
44
+ next if line.strip[0] == "#"
45
+
46
+ next_line = lines[i + 1]
47
+ indent, next_indent = text_indent(line), text_indent(next_line)
48
+ command = parse_line(line)
49
+
50
+ # Grab sub lines if possible
51
+ if next_indent > indent
52
+ j = i + 1
53
+ sublines = []
54
+ while(look_ahead_line = lines[j])
55
+ look_ahead_indent = text_indent(look_ahead_line)
56
+ if look_ahead_indent > indent
57
+ sublines << lines.slice!(j)
58
+ else
59
+ break
60
+ end
61
+ end
62
+ command.sublines = parse_lines sublines
63
+ end
64
+ data << command
65
+ end
66
+ data
67
+ end
68
+
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,58 @@
1
+
2
+
3
+
4
+ grammar Sexp
5
+
6
+ rule body
7
+ (expression / variable / identifier / string / space)* {
8
+ def value
9
+ elements.delete_if do |e|
10
+ !e.respond_to? :value
11
+ end
12
+ elements.map{|e| e.value}
13
+ end
14
+ }
15
+ end
16
+
17
+
18
+ rule expression
19
+ space? '{' body '}' space? {
20
+ def value
21
+ body.elements.delete_if do |e|
22
+ !e.respond_to? :value
23
+ end
24
+ body.elements.map{|e| e.value}
25
+ end
26
+ }
27
+ end
28
+
29
+
30
+ rule variable
31
+ '$' identifier {
32
+ def value
33
+ Aster::Variable.new identifier.text_value.to_sym
34
+ end
35
+ }
36
+ end
37
+
38
+ rule identifier
39
+ [a-zA-Z0-9] [a-zA-Z0-9]* {
40
+ def value
41
+ text_value
42
+ end
43
+ }
44
+ end
45
+
46
+ rule string
47
+ '"' ([^"\\] / "\\" . )* '"' {
48
+ def value
49
+ text_value
50
+ end
51
+ }
52
+ end
53
+
54
+ rule space
55
+ [\s]+
56
+ end
57
+
58
+ end
@@ -0,0 +1,11 @@
1
+ module Aster
2
+ class Variable
3
+ def initialize(name)
4
+ @name = name.to_sym
5
+ end
6
+
7
+ def name
8
+ @name
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Aster
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,19 @@
1
+
2
+
3
+ server web
4
+
5
+ set max-instances 12
6
+
7
+ set instance-methods
8
+
9
+ function after-create-hook
10
+ configure
11
+
12
+ function configure
13
+ run install_base_ubuntu.aster
14
+ exec sudo apt-get install nginx
15
+
16
+ function reboot
17
+ exec sudo reboot
18
+
19
+
data/test/helper.rb ADDED
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), *%w(.. lib aster))
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+
@@ -0,0 +1,18 @@
1
+ require_relative './helper'
2
+
3
+ class TestEnvironment < Test::Unit::TestCase
4
+
5
+ def test_not
6
+ e = Aster::Environment.new
7
+ #assert_equal "no", e.eval("not yes")
8
+ #assert_equal "yes", e.eval("not no")
9
+ end
10
+
11
+ def test_function
12
+ e = Aster::Environment.new
13
+ e.eval "function test arg1 arg2\n echo $arg1 and $arg2"
14
+ e.eval "test one two"
15
+ assert_equal("one and two", e.stdout)
16
+ end
17
+
18
+ end
@@ -0,0 +1,58 @@
1
+ require_relative './helper'
2
+
3
+ class TestParser < Test::Unit::TestCase
4
+
5
+ def parse_line(text)
6
+ p = Aster::Parser.new
7
+ p.send :raw_parse_line, text
8
+ end
9
+
10
+ def parse text
11
+ p = Aster::Parser.new
12
+ p.parse text
13
+ end
14
+
15
+ def text_indent(text)
16
+ p = Aster::Parser.new
17
+ p.send :text_indent, text
18
+ end
19
+
20
+ def test_leading_indent()
21
+ assert_equal 0, text_indent('')
22
+ assert_equal 1, text_indent(' ')
23
+ assert_equal 2, text_indent(' ')
24
+ assert_equal -1, text_indent(' ')
25
+ assert_equal -1, text_indent(' ')
26
+ end
27
+
28
+ def test_line_parse
29
+ assert_equal ["a"], parse_line("a")
30
+ assert_equal ["a", "a"], parse_line("a a")
31
+ assert_equal [:a, :b], parse_line("{$a $b}").first.map{|v| v.name.to_sym}
32
+ assert_equal ["upload", "\"asdf.jpg\""], parse_line(%q(upload "asdf.jpg"))
33
+ end
34
+
35
+ def test_command_parse
36
+ c = parse "asdf one two"
37
+ assert_equal c.first.function_name, :asdf
38
+ end
39
+
40
+ def test_asdf
41
+ p = Aster::Parser.new
42
+ tree = p.parse "if {not {test}}"
43
+ command = tree.first
44
+ end
45
+
46
+ def test_parse
47
+ parser = Aster::Parser.new
48
+ file = "
49
+ function test asdr
50
+ exec test
51
+
52
+ function test2 asdf
53
+ exec
54
+ "
55
+ tree = parser.parse file
56
+ end
57
+
58
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aster
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sam Murphy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: treetop
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: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - sam.murphy@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - TODO
82
+ - aster.gemspec
83
+ - lib/aster.rb
84
+ - lib/aster/command.rb
85
+ - lib/aster/environment.rb
86
+ - lib/aster/function.rb
87
+ - lib/aster/parser.rb
88
+ - lib/aster/sexp.treetop
89
+ - lib/aster/variable.rb
90
+ - lib/aster/version.rb
91
+ - test/examples/web_server.aster
92
+ - test/helper.rb
93
+ - test/test_environment.rb
94
+ - test/test_parser.rb
95
+ homepage: ''
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.0.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: A programming language for configuring servers
119
+ test_files:
120
+ - test/examples/web_server.aster
121
+ - test/helper.rb
122
+ - test/test_environment.rb
123
+ - test/test_parser.rb