dslize 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ Gemfile.lock
16
+
17
+ # YARD artifacts
18
+ .yardoc
19
+ _yardoc
20
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # DSLize #
2
+
3
+ ## Summary ##
4
+
5
+ Finally an way to generate code with a custom DSL the ruby way !
6
+
7
+ ### In brief: ###
8
+
9
+ * Use real ruby classes to define your DSL
10
+ * Add custom behaviors defining ruby methods
11
+ * Create custom formatters/generators extending a base class
12
+ * Module `DSLize::Methods` defines how your attributes are interpreted, include `DSLize::Methods::Base` to has the standard attributes
13
+ * Module `DSLize::Definition` defines your DSL
14
+
15
+ ## Installation ##
16
+
17
+ gem install dslize
18
+
19
+ then:
20
+
21
+ require "dslize"
22
+
23
+ ## Sample ##
24
+
25
+ #! /usr/bin/env ruby
26
+
27
+ require 'dslize'
28
+
29
+ module DSLize::Methods
30
+ include DSLize::Methods::Base
31
+
32
+ def self.my_first_custom_method(attr, args = {})
33
+ args[:type] = :custom
34
+ DSLize.current_object[attr] = args
35
+ end
36
+
37
+ def self.my_second_custom_method
38
+ DSLize.current_object['baz'] = true
39
+ end
40
+
41
+ end
42
+
43
+ module DSLize::Definition
44
+
45
+ class City
46
+ string :name
47
+ integer :population, :default => 42
48
+ end
49
+
50
+ class Country
51
+ string :name, :default => 'France'
52
+
53
+ has_many City, :as => :cities
54
+
55
+ has_one City, :as => :capital
56
+ end
57
+
58
+ class World
59
+ root
60
+
61
+ has_many Country
62
+
63
+ my_first_custom_method :foo, :default => 'bar'
64
+
65
+ my_second_custom_method
66
+ end
67
+
68
+ class Planet
69
+ abstract
70
+ end
71
+
72
+ class GazPlanet < Planet
73
+ end
74
+
75
+ class WaterPlanet < Planet
76
+ end
77
+
78
+ end
79
+
80
+ class MyCustomFormatter < DSLize::Formatter::Base
81
+ def do_stuff
82
+ # with self.object
83
+ # and self.superclasses
84
+ end
85
+ end
86
+
87
+ DSLize::Formatter::XSD.new.generate!("/tmp/schema.xsd")
88
+ MyCustomFormatter.new.do_stuff
89
+
90
+ ## About me ##
91
+
92
+ Sylvain UTARD - http://sylvain.utard.info
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
data/dslize.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dslize/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "dslize"
7
+ s.version = DSLize::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['redox']
10
+ s.email = ['sylvain.utard@gmail.com']
11
+ s.homepage = "https://github.com/utard/dslize"
12
+ s.summary = %q{DSL made easy}
13
+ s.description = %q{}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+ s.requirements << 'xpain'
20
+ end
@@ -0,0 +1,91 @@
1
+ class Object
2
+
3
+ def self.method_missing(method_name, *args, &block)
4
+ return DSLize::Methods.send(method_name, *args) if self.name['DSLize::Definition::'] and DSLize::Methods.respond_to?(method_name)
5
+ super.method_missing(method_name, args, &block)
6
+ end
7
+
8
+ def self.inherited(subclass)
9
+ if subclass.name['DSLize::Definition::']
10
+ superclass = subclass.superclass
11
+ subclass = subclass.name.split('::').last
12
+ DSLize.objects ||= {}
13
+ DSLize.objects[subclass] = {}
14
+ DSLize.current_object = DSLize.objects[subclass]
15
+ DSLize.superclasses ||= {}
16
+ DSLize.superclasses[subclass] = superclass.name.split('::').last
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+ module DSLize
23
+
24
+ class << self
25
+ attr_accessor :objects
26
+ attr_accessor :current_object
27
+ attr_accessor :superclasses
28
+ end
29
+
30
+ module Methods
31
+
32
+ module Base
33
+
34
+ def self.included(receiver)
35
+ receiver.extend(ClassMethods)
36
+ end
37
+
38
+ module ClassMethods
39
+
40
+ def string(attr, args = {})
41
+ attribute(:string, attr, args)
42
+ end
43
+
44
+ def integer(attr, args = {})
45
+ attribute(:integer, attr, args)
46
+ end
47
+
48
+ def double(attr, args = {})
49
+ attribute(:double, attr, args)
50
+ end
51
+
52
+ def has_many(attr, args = {})
53
+ relation(:has_many, attr, args)
54
+ end
55
+
56
+ def has_one(attr, args = {})
57
+ relation(:has_one, attr, args)
58
+ end
59
+
60
+ def root
61
+ DSLize.current_object[:root] = true
62
+ end
63
+
64
+ def abstract
65
+ DSLize.current_object[:abstract] = true
66
+ end
67
+
68
+ private
69
+ def attribute(type, name, args)
70
+ args[:type] = type
71
+ DSLize.current_object[:attributes] = {}
72
+ DSLize.current_object[:attributes][name] = args
73
+ end
74
+
75
+ def relation(type, name, args)
76
+ name = (name.name rescue name.to_s).split('::').last
77
+ args[:type] = name
78
+ if as = args.delete(:as)
79
+ name = as.to_s
80
+ end
81
+ DSLize.current_object[type] ||= {}
82
+ DSLize.current_object[type][name] = args
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,16 @@
1
+ module DSLize
2
+ module Formatter
3
+
4
+ class Base
5
+ attr_accessor :objects
6
+ attr_accessor :superclasses
7
+
8
+ def initialize
9
+ self.objects = DSLize.objects
10
+ self.superclasses = DSLize.superclasses
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,91 @@
1
+ require File.dirname(__FILE__) + '/formatter'
2
+
3
+ module DSLize
4
+ module Formatter
5
+
6
+ class XSD < Base
7
+
8
+ def generate!(*args)
9
+ schema = XPain::Builder.new do |xsd|
10
+ xsd.schema do
11
+ objects.each do |name, options|
12
+ parent = superclasses[name]
13
+
14
+ xsd.element(name, :type => (options[:type] or name))
15
+
16
+ xsd.complexType({ :name => name, :abstract => options[:abstract], :mixed => false }.select { |k,v| !v.nil? }) do
17
+ extends_base_if_needed(xsd, parent) do
18
+
19
+ # relations
20
+ xsd.sequence do
21
+ { :has_one => nil, :has_many => "unbounded"}.each do |relation, max_occurs|
22
+ (options[relation] or []).each do |k, v|
23
+ named_object_if_needed(xsd, k, v) do
24
+ xsd.element(nil, { :ref => (v[:type] or k), :maxOccurs => max_occurs }.select { |k,v| !v.nil? })
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # attributes
31
+ (options[:attributes] or []).each do |k, v|
32
+ xsd.attribute({ :name => k, :default => v[:default], :type => xsd_type(v[:type]) }.select { |k,v| !v.nil? })
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+
42
+ File.open(args[0], "w") do |f|
43
+ f << schema.to_xml.gsub(' name=""', '') # xpain is buggy and always write a name on <element>
44
+ end
45
+ end
46
+
47
+ private
48
+ def extends_base_if_needed(xsd, parent)
49
+ if parent != "Object"
50
+ xsd.complexContent :mixed => false do
51
+ xsd.extension :base => parent do
52
+ yield
53
+ end
54
+ end
55
+ else
56
+ yield
57
+ end
58
+ end
59
+
60
+ def named_object_if_needed(xsd, name, options)
61
+ if options[:type] and name != options[:type]
62
+ xsd.element name, :contains => 'none' do
63
+ xsd.complexType do
64
+ xsd.sequence do
65
+ yield
66
+ end
67
+ end
68
+ end
69
+ else
70
+ yield
71
+ end
72
+ end
73
+
74
+ def xsd_type(type)
75
+ case type
76
+ when :float
77
+ "xsd:double"
78
+ when :integer
79
+ "xsd:int"
80
+ when :string
81
+ "xsd:string"
82
+ else
83
+ type
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,3 @@
1
+ module DSLize
2
+ VERSION = "0.0.1"
3
+ end
data/lib/dslize.rb ADDED
@@ -0,0 +1,6 @@
1
+ module DSLize
2
+ require 'xpain'
3
+
4
+ require File.dirname(__FILE__) + '/dslize/dslize'
5
+ require File.dirname(__FILE__) + '/dslize/formatter/xsd_formatter'
6
+ end
data/sample.rb ADDED
@@ -0,0 +1,61 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ begin
4
+ # dev mode
5
+ require File.dirname(__FILE__) + '/lib/dslize'
6
+ rescue
7
+ require 'dslize'
8
+ end
9
+
10
+ module DSLize::Methods
11
+ include DSLize::Methods::Base
12
+
13
+ def self.my_first_custom_method(attr, args = {})
14
+ args[:type] = :custom
15
+ DSLize.current_object[attr] = args
16
+ end
17
+
18
+ def self.my_second_custom_method
19
+ DSLize.current_object['baz'] = true
20
+ end
21
+
22
+ end
23
+
24
+ module DSLize::Definition
25
+
26
+ class City
27
+ string :name
28
+ integer :population, :default => 42
29
+ end
30
+
31
+ class Country
32
+ string :name, :default => 'France'
33
+
34
+ has_many City, :as => :cities
35
+
36
+ has_one City, :as => :capital
37
+ end
38
+
39
+ class World
40
+ root
41
+
42
+ has_many Country
43
+
44
+ my_first_custom_method :foo, :default => 'bar'
45
+
46
+ my_second_custom_method
47
+ end
48
+
49
+ class Planet
50
+ abstract
51
+ end
52
+
53
+ class GazPlanet < Planet
54
+ end
55
+
56
+ class WaterPlanet < Planet
57
+ end
58
+
59
+ end
60
+
61
+ DSLize::Formatter::XSD.new.generate!(ARGV[0])
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dslize
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - redox
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-07-10 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: ""
22
+ email:
23
+ - sylvain.utard@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - README.md
34
+ - Rakefile
35
+ - dslize.gemspec
36
+ - lib/dslize.rb
37
+ - lib/dslize/dslize.rb
38
+ - lib/dslize/formatter/formatter.rb
39
+ - lib/dslize/formatter/xsd_formatter.rb
40
+ - lib/dslize/version.rb
41
+ - sample.rb
42
+ has_rdoc: true
43
+ homepage: https://github.com/utard/dslize
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements:
66
+ - xpain
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.6
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: DSL made easy
72
+ test_files: []
73
+