defined-by 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Lance Pollard (lancejpollard@gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # DefinedBy
2
+
3
+ > Advanced DSL and Dynamic class generation for Ruby
4
+
5
+ ## When do I is this?
6
+
7
+ - If you want to use a DSL to cut down on your code base
8
+ - If you need that DSL to create classes
9
+ - If you have a base class (e.g. `Widget`) and want to subclass it dozens of times but it's overkill to create separate classes for it manually.
10
+ - Define template classes (default values for subclasses)
11
+
12
+ ## All at once
13
+
14
+ class Widget
15
+ class << self
16
+ def define(&block)
17
+ DefinedBy::DSL(&block).map do |key, value, dsl_block|
18
+ define_class(key, self).new(:name => key.to_s, :description => value)
19
+ end
20
+ end
21
+ end
22
+
23
+ attr_accessor :name, :description
24
+
25
+ def initialize(attributes = {})
26
+ attributes.each do |key, value|
27
+ self.send("#{key.to_s}=", value)
28
+ end
29
+ end
30
+ end
31
+
32
+ def Widget(&block)
33
+ Widget.define(&block)
34
+ end
35
+
36
+ widgets = Widget do
37
+ widget_a "This widget does X"
38
+ widget_b "This does Y"
39
+ end
40
+
41
+ puts widgets.inspect
42
+ #=> [
43
+ #<WidgetA:0x5c3348 @description="This widget does X", @name="widget_a">,
44
+ #<WidgetB:0x5c2970 @description="This does Y", @name="widget_b">
45
+ ]
@@ -0,0 +1,78 @@
1
+ require 'rake'
2
+ require "rake/rdoctask"
3
+ require 'rake/gempackagetask'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+ s.name = "defined-by"
7
+ s.authors = ["Lance Pollard"]
8
+ s.version = "0.0.5"
9
+ s.summary = "Advanced DSL and Dynamic class generation for Ruby"
10
+ s.homepage = "http://github.com/viatropos/defined-by"
11
+ s.email = "lancejpollard@gmail.com"
12
+ s.description = "Advanced DSL and Dynamic class generation for Ruby"
13
+ s.has_rdoc = false
14
+ s.rubyforge_project = "defined-by"
15
+ s.platform = Gem::Platform::RUBY
16
+ s.files = %w(README.markdown Rakefile MIT-LICENSE.markdown) + Dir["{lib,test}/**/*"] - Dir["test/tmp"]
17
+ s.require_path = "lib"
18
+ end
19
+
20
+ Rake::GemPackageTask.new(spec) do |pkg|
21
+ pkg.gem_spec = spec
22
+ pkg.package_dir = "pkg"
23
+ end
24
+
25
+ desc 'run unit tests'
26
+ task :test do
27
+ Dir["test/**/*"].each do |file|
28
+ next unless File.basename(file) =~ /test_/
29
+ next unless File.extname(file) == ".rb"
30
+ system "ruby #{file}"
31
+ end
32
+ end
33
+
34
+ desc "Create .gemspec file (useful for github)"
35
+ task :gemspec do
36
+ File.open("pkg/#{spec.name}.gemspec", "w") do |f|
37
+ f.puts spec.to_ruby
38
+ end
39
+ end
40
+
41
+ desc "Build the gem into the current directory"
42
+ task :gem => :gemspec do
43
+ `gem build pkg/#{spec.name}.gemspec`
44
+ end
45
+
46
+ desc "Publish gem to rubygems"
47
+ task :publish => [:package] do
48
+ %x[gem push pkg/#{spec.name}-#{spec.version}.gem]
49
+ end
50
+
51
+ desc "Print a list of the files to be put into the gem"
52
+ task :manifest do
53
+ File.open("Manifest", "w") do |f|
54
+ spec.files.each do |file|
55
+ f.puts file
56
+ end
57
+ end
58
+ end
59
+
60
+ desc "Install the gem locally"
61
+ task :install => [:package] do
62
+ File.mkdir("pkg") unless File.exists?("pkg")
63
+ command = "gem install pkg/#{spec.name}-#{spec.version} --no-ri --no-rdoc"
64
+ command = "sudo #{command}" if ENV["SUDO"] == true
65
+ sh %{#{command}}
66
+ end
67
+
68
+ desc "Generate the rdoc"
69
+ Rake::RDocTask.new do |rdoc|
70
+ files = ["README.markdown", "lib/**/*.rb"]
71
+ rdoc.rdoc_files.add(files)
72
+ rdoc.main = "README.markdown"
73
+ rdoc.title = spec.summary
74
+ end
75
+
76
+ task :yank do
77
+ `gem yank #{spec.name} -v #{spec.version}`
78
+ end
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/defined-by/*"].each do |file|
2
+ require file if File.extname(file) == ".rb"
3
+ end
@@ -0,0 +1,7 @@
1
+ def define_class(name, superclass = Object, &block)
2
+ name = name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
3
+ eval("class #{name} < #{superclass}; end")
4
+ clazz = eval(name)
5
+ clazz.class_eval(&block) if block_given?
6
+ clazz
7
+ end
@@ -0,0 +1,11 @@
1
+ def define_module(name, &block)
2
+ name = name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
3
+ parts = name.split("::")
4
+ parts.each_with_index do |part, index|
5
+ sub_name = parts[0..index].join("::")
6
+ eval("module #{sub_name}; end")
7
+ end
8
+ clazz = eval(name)
9
+ clazz.class_eval(&block) if block_given?
10
+ clazz
11
+ end
@@ -0,0 +1,35 @@
1
+ module DefinedBy
2
+ class DSL
3
+ def initialize(&block)
4
+ @values = []
5
+ instance_eval(&block) if block_given?
6
+ end
7
+
8
+ def <<(array)
9
+ @values << array
10
+ end
11
+
12
+ def each(&block)
13
+ @values.each do |array|
14
+ yield(array[0], array[1], array[2])
15
+ end
16
+ end
17
+
18
+ def map(&block)
19
+ @values.map do |array|
20
+ yield(array[0], array[1], array[2])
21
+ end
22
+ end
23
+
24
+ def method_missing(method, *args, &block)
25
+ args = *args
26
+ self << [method.to_sym, args, block]
27
+ end
28
+ end
29
+
30
+ class << self
31
+ def DSL(&block)
32
+ DSL.new(&block)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,51 @@
1
+ module DefinedBy
2
+ module MissingConstant
3
+ class Definition
4
+ class << self
5
+ attr_accessor :definitions
6
+
7
+ def for(const_name)
8
+ definitions.detect do |definition|
9
+ definition.match(const_name)
10
+ end.constant rescue nil
11
+ end
12
+
13
+ def definitions
14
+ @definitions ||= []
15
+ end
16
+
17
+ def define!(&block)
18
+ DefinedBy::DSL(&block).each do |key, value, dsl_block|
19
+ definitions << Definition.new(value.first, value.last)
20
+ end
21
+ end
22
+ end
23
+
24
+ attr_reader :pattern, :replacement, :constant
25
+ def initialize(pattern, replacement)
26
+ @pattern, @replacement = pattern, replacement
27
+ end
28
+
29
+ def match(const_name)
30
+ if const_name.to_s.match(pattern)
31
+ @constant = const_name.to_s.gsub(pattern, replacement).to_sym
32
+ else
33
+ @constant = nil
34
+ end
35
+ end
36
+ end
37
+
38
+ # def const_missing(const_name)
39
+ # if new_constant = Definition.for(const_name)
40
+ # super(new_constant)
41
+ # end
42
+ # super(const_name)
43
+ # end
44
+ end
45
+
46
+ def self.MissingConstants(&block)
47
+ DefinedBy::MissingConstant::Definition.define!(&block)
48
+ end
49
+ end
50
+
51
+ #Class.instance_eval { include DefinedBy::MissingConstant }
File without changes
@@ -0,0 +1,27 @@
1
+ class Widget
2
+ class << self
3
+ def define(&block)
4
+ DefinedBy::DSL(&block).map do |key, value, dsl_block|
5
+ define_class(key.to_s.camelize, self).class_eval <<-EOF
6
+ def initialize(attributes = {})
7
+ attributes[:name] ||= #{key.to_s.inspect}
8
+ attributes[:description] ||= #{value.to_s.inspect}
9
+ super(attributes)
10
+ end
11
+ EOF
12
+ end
13
+ end
14
+ end
15
+
16
+ attr_accessor :name, :description
17
+
18
+ def initialize(attributes = {})
19
+ attributes.each do |key, value|
20
+ self.send("#{key.to_s}=", value)
21
+ end
22
+ end
23
+ end
24
+
25
+ def Widget(&block)
26
+ Widget.define(&block)
27
+ end
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class DSLTest < ActiveSupport::TestCase
4
+
5
+ context "DSL" do
6
+
7
+ context "define widgets" do
8
+ setup do
9
+ widgets = Widget do
10
+ widget_a "This widget does X"
11
+ widget_b "This does Y"
12
+ end
13
+ end
14
+
15
+ should "have 2 widget classes" do
16
+ assert WidgetA
17
+ assert WidgetB
18
+ end
19
+
20
+ should "be able to instantiate the two widget classes" do
21
+ @a = WidgetA.new
22
+ @b = WidgetB.new
23
+
24
+ assert @a
25
+ assert @b
26
+
27
+ assert_equal "This widget does X", @a.description
28
+ assert_equal "This does Y", @b.description
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ context "Module" do
35
+ setup do
36
+ define_module("Lance::Pollard") do
37
+ class << self
38
+ def acts_as_lance_pollard
39
+ "yep"
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ should "have defined the modules" do
46
+ assert Lance::Pollard
47
+ assert_equal "yep", Lance::Pollard.acts_as_lance_pollard
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,18 @@
1
+ require "rubygems"
2
+ require "ruby-debug"
3
+ gem 'test-unit'
4
+ require "test/unit"
5
+ require 'active_support'
6
+ require 'active_support/test_case'
7
+ require 'shoulda'
8
+ require 'shoulda/active_record'
9
+ require 'logger'
10
+
11
+ this = File.expand_path(File.dirname(__FILE__))
12
+
13
+ require File.expand_path(File.join(this, '/../lib/defined-by'))
14
+
15
+ Dir["#{this}/lib/*"].each { |c| require c if File.extname(c) == ".rb" }
16
+
17
+ ActiveSupport::TestCase.class_eval do
18
+ end
@@ -0,0 +1,62 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class MissingConstantTest < ActiveSupport::TestCase
4
+
5
+ context "MissingConstant" do
6
+
7
+ should "not have the constant by default" do
8
+ assert ::UserProfile
9
+ end
10
+
11
+ context "define the base" do
12
+ setup do
13
+ class ::Object
14
+ class << self
15
+ def profile(&block)
16
+ define_class("::#{self.name}Profile", "::Profile") do
17
+ attr_accessor :profile
18
+
19
+ def profile
20
+ @profile ||= {}
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ class ::Profile
28
+
29
+ end
30
+ end
31
+
32
+ should "have defined the profile" do
33
+
34
+ end
35
+
36
+ context "define the meat" do
37
+ setup do
38
+ class ::User
39
+ profile
40
+ end
41
+ end
42
+
43
+ should "have defined the constant now" do
44
+ assert ::UserProfile
45
+ end
46
+ end
47
+ end
48
+
49
+ context "DSL" do
50
+ setup do
51
+ DefinedBy::MissingConstants() do
52
+ match %r{\w+(Profile)$}, "\\1"
53
+ end
54
+ end
55
+
56
+ should "define the dsl" do
57
+ assert_equal 1, DefinedBy::MissingConstant::Definition.definitions.length
58
+ assert_equal :Profile, DefinedBy::MissingConstant::Definition.for(:UserProfile)
59
+ end
60
+ end
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: defined-by
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 5
10
+ version: 0.0.5
11
+ platform: ruby
12
+ authors:
13
+ - Lance Pollard
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-13 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Advanced DSL and Dynamic class generation for Ruby
23
+ email: lancejpollard@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - README.markdown
32
+ - Rakefile
33
+ - MIT-LICENSE.markdown
34
+ - lib/defined-by/define_class.rb
35
+ - lib/defined-by/define_module.rb
36
+ - lib/defined-by/dsl.rb
37
+ - lib/defined-by/missing_constant.rb
38
+ - lib/defined-by.rb
39
+ - test/lib/missing.rb
40
+ - test/lib/widget.rb
41
+ - test/test_dsl.rb
42
+ - test/test_helper.rb
43
+ - test/test_missing_constant.rb
44
+ has_rdoc: true
45
+ homepage: http://github.com/viatropos/defined-by
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project: defined-by
74
+ rubygems_version: 1.3.7
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Advanced DSL and Dynamic class generation for Ruby
78
+ test_files: []
79
+