contextr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,162 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ require 'hoe'
11
+ include FileUtils
12
+ require File.join(File.dirname(__FILE__), 'lib', 'contextr', 'version')
13
+
14
+ AUTHOR = 'schmidt' # can also be an array of Authors
15
+ EMAIL = "ruby@schmidtwisser.de"
16
+ DESCRIPTION = "The goal is to equip Ruby with an API to allow context-oriented programming."
17
+ GEM_NAME = 'contextr' # what ppl will type to install your gem
18
+ RUBYFORGE_PROJECT = 'contextr' # The unix name for your project
19
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
21
+
22
+ NAME = "contextr"
23
+ REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
+ VERS = ContextR::VERSION::STRING + (REV ? ".#{REV}" : "")
25
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
26
+ RDOC_OPTS = ['--quiet', '--title', 'contextr documentation',
27
+ "--opname", "index.html",
28
+ "--line-numbers",
29
+ "--main", "README",
30
+ "--inline-source"]
31
+
32
+ class Hoe
33
+ def extra_deps
34
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
+ end
36
+ end
37
+
38
+ # Generate all the Rake tasks
39
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
40
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
41
+ p.author = AUTHOR
42
+ p.description = DESCRIPTION
43
+ p.email = EMAIL
44
+ p.summary = DESCRIPTION
45
+ p.url = HOMEPATH
46
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
47
+ p.test_globs = ["test/**/test_*.rb"]
48
+ p.clean_globs = CLEAN #An array of file patterns to delete on clean.
49
+
50
+ # == Optional
51
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
52
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
53
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
54
+ end
55
+
56
+
57
+ desc 'Generate website files'
58
+ task :website_generate do
59
+ Dir['website/**/*.txt'].each do |txt|
60
+ sh %{ ruby scripts/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
61
+ end
62
+ end
63
+
64
+ desc 'Upload website files to rubyforge'
65
+ task :website_upload do
66
+ config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
67
+ host = "#{config["username"]}@rubyforge.org"
68
+ remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/"
69
+ # remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
70
+ local_dir = 'website'
71
+ sh %{rsync -av --delete-excluded --exclude=".*/" #{local_dir}/ #{host}:#{remote_dir}}
72
+ end
73
+
74
+ desc 'Generate and upload website files'
75
+ task :website => [:website_generate, :website_upload]
76
+
77
+ desc 'Release the website and new gem version'
78
+ task :deploy => [:check_version, :website, :release]
79
+
80
+ task :check_version do
81
+ unless ENV['VERSION']
82
+ puts 'Must pass a VERSION=x.y.z release version'
83
+ exit
84
+ end
85
+ unless ENV['VERSION'] == VERS
86
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
87
+ exit
88
+ end
89
+ end
90
+
91
+
92
+ # Most of this code was taken from the Rubinius Rakefile.
93
+ # Thanks for the help.
94
+
95
+ ROOT = File.expand_path(File.dirname(__FILE__))
96
+
97
+ def load_files(files)
98
+ files.each do |path|
99
+ begin
100
+ require(path)
101
+ rescue Object => e
102
+ STDERR.puts "Unable to load #{path}. #{e.message} (#{e.class})"
103
+ end
104
+ end
105
+ end
106
+ def require_files(files)
107
+ files.each do |path|
108
+ begin
109
+ require(path)
110
+ rescue Object => e
111
+ STDERR.puts "Unable to load #{path}. #{e.message} (#{e.class})"
112
+ end
113
+ end
114
+ end
115
+
116
+ begin
117
+ require 'spec/rake/spectask'
118
+ rescue LoadError
119
+ raise <<-EOM
120
+ Unable to load spec/rake/spectask. RSpec is a requirement to build Rubinius.
121
+ Please install RSpec before building (http://rspec.rubyforge.org).
122
+ EOM
123
+ end
124
+
125
+ # Task class extensions
126
+ paths = Dir[ File.join(File.dirname(__FILE__), 'rake/*') ]
127
+ require_files(paths)
128
+ #
129
+ # Other tasks
130
+ paths = Dir[ File.join(File.dirname(__FILE__), 'tasks/*') ]
131
+ load_files(paths)
132
+
133
+ desc "Run all specs and tests"
134
+ task :default => [ :spec, :test ]
135
+
136
+ task :spec => 'spec:all'
137
+
138
+ # Generate all the spec tasks
139
+ namespace :spec do
140
+
141
+ spec_targets = %w(contextr core_ext)
142
+
143
+ spec_targets.each do | group |
144
+ spec_files = Dir[ File.join( File.dirname(__FILE__),
145
+ "spec/#{group}/*_spec.rb") ]
146
+
147
+ GroupSpecTask.new( group )
148
+
149
+ namespace group do
150
+ spec_files.each do | file |
151
+ SpecificGroupSpecTask.new( File.basename( file, '_spec.rb'), group )
152
+ end
153
+ end
154
+ end
155
+
156
+ desc "Run all specs."
157
+ task :all => spec_targets.collect! { | group | 'spec:' << group }
158
+ end
159
+
160
+ desc "Run all benchmarks - currently none"
161
+ task :benchmark
162
+
@@ -0,0 +1,67 @@
1
+ require "rubygems"
2
+ require "contextr"
3
+
4
+ class Person
5
+ layer :address, :education
6
+
7
+ attr_accessor :name, :address, :university
8
+
9
+ def initialize name, address, university
10
+ self.name = name
11
+ self.address = address
12
+ self.university = university
13
+ end
14
+
15
+ def to_s
16
+ "Name: #{name}"
17
+ end
18
+
19
+ address.post :to_s do | n |
20
+ n.return_value += "; Address: #{address}"
21
+ end
22
+
23
+ education.post :to_s do | n |
24
+ n.return_value += ";\n[Education] #{university}"
25
+ end
26
+ end
27
+
28
+ class University
29
+ layer :address
30
+
31
+ attr_accessor :name, :address
32
+
33
+ def initialize name, address
34
+ self.name = name
35
+ self.address = address
36
+ end
37
+
38
+ def to_s
39
+ "Name: #{name}"
40
+ end
41
+
42
+ address.post :to_s do | n |
43
+ n.return_value += "; Address: #{address}"
44
+ end
45
+ end
46
+
47
+
48
+ hpi = University.new( "Hasso-Plattner-Institut", "Potsdam" )
49
+ somePerson = Person.new( "Gregor Schmidt", "Berlin", hpi )
50
+
51
+ puts
52
+ puts somePerson
53
+ ContextR::with_layers :address do
54
+ puts
55
+ puts somePerson
56
+
57
+ ContextR::with_layers :education do
58
+ puts
59
+ puts somePerson
60
+
61
+ ContextR::without_layers :address do
62
+ puts
63
+ puts somePerson
64
+ end
65
+ end
66
+ end
67
+ puts
@@ -0,0 +1,123 @@
1
+ require "rubygems"
2
+ require "contextr"
3
+
4
+ require 'test/unit'
5
+ require 'benchmark'
6
+
7
+ class FibonacciCalculator
8
+ def compute fixnum
9
+ if fixnum == 1 or fixnum == 0
10
+ fixnum
11
+ elsif fixnum < 0
12
+ raise ArgumentError, "Fibonacci not defined for negative numbers"
13
+ else
14
+ compute(fixnum - 1) + compute(fixnum - 2)
15
+ end
16
+ end
17
+
18
+ layer :fib_pre_post, :fib_wrap
19
+ attr_accessor :cache
20
+
21
+ fib_pre_post.pre :compute do | nature |
22
+ self.cache ||= {}
23
+ if self.cache.key? nature.arguments.first
24
+ nature.break! self.cache[nature.arguments.first]
25
+ end
26
+ end
27
+
28
+ fib_pre_post.post :compute do | nature |
29
+ self.cache[nature.arguments.first] = nature.return_value
30
+ end
31
+
32
+ fib_wrap.wrap :compute do | nature |
33
+ self.cache ||= {}
34
+ if self.cache.key? nature.arguments.first
35
+ nature.return_value = self.cache[nature.arguments.first]
36
+ else
37
+ nature.call_next
38
+ self.cache[nature.arguments.first] = nature.return_value
39
+ end
40
+ end
41
+ end
42
+
43
+ class Fixnum
44
+ def fibonacci
45
+ if self == 1 or self == 0
46
+ self
47
+ elsif self < 0
48
+ raise ArgumentError, "Fibonacci not defined for negative numbers"
49
+ else
50
+ old_fib, fib = 0, 1
51
+ for i in 2..self
52
+ fib, old_fib = old_fib + fib, fib
53
+ end
54
+ fib
55
+ end
56
+ end
57
+ end
58
+
59
+ class FibonacciTest < Test::Unit::TestCase
60
+ def setup
61
+ @fibonacci = FibonacciCalculator.new
62
+ end
63
+
64
+ def test_basic_function
65
+ Benchmark.bm(20) do |x|
66
+ x.report("Recursive:") {
67
+ assert_equal 0, @fibonacci.compute( 0 )
68
+ assert_equal 1, @fibonacci.compute( 1 )
69
+ assert_equal 1, @fibonacci.compute( 2 )
70
+ assert_equal 55, @fibonacci.compute( 10 )
71
+ assert_equal 6765, @fibonacci.compute( 20 )
72
+ # The following are too hard for the simple solution
73
+ assert_equal 75_025, 25.fibonacci
74
+ assert_equal 9227465, 35.fibonacci
75
+ assert_equal 280571172992510140037611932413038677189525,
76
+ 200.fibonacci
77
+ assert_equal 176023680645013966468226945392411250770384383304492191886725992896575345044216019675,
78
+ 400.fibonacci
79
+ }
80
+ end
81
+ end
82
+
83
+ def test_layered_function_with_pre_post
84
+ Benchmark.bm(20) do |x|
85
+ x.report("Layered Pre/Post:") {
86
+ ContextR.with_layers :fib_pre_post do
87
+ assert_equal 0, @fibonacci.compute( 0 )
88
+ assert_equal 1, @fibonacci.compute( 1 )
89
+ assert_equal 1, @fibonacci.compute( 2 )
90
+ assert_equal 2, @fibonacci.compute( 3 )
91
+ assert_equal 55, @fibonacci.compute( 10 )
92
+ assert_equal 6765, @fibonacci.compute( 20 )
93
+ assert_equal 75_025, @fibonacci.compute( 25 )
94
+ assert_equal 9227465, @fibonacci.compute( 35 )
95
+ assert_equal 280571172992510140037611932413038677189525,
96
+ @fibonacci.compute( 200 )
97
+ assert_equal 176023680645013966468226945392411250770384383304492191886725992896575345044216019675,
98
+ @fibonacci.compute( 400 )
99
+ end
100
+ }
101
+ end
102
+ end
103
+
104
+ def test_layered_function_with_wrap
105
+ Benchmark.bm(20) do |x|
106
+ x.report("Layered Wrap:") {
107
+ ContextR.with_layers :fib_wrap do
108
+ assert_equal 0, @fibonacci.compute( 0 )
109
+ assert_equal 1, @fibonacci.compute( 1 )
110
+ assert_equal 1, @fibonacci.compute( 2 )
111
+ assert_equal 55, @fibonacci.compute( 10 )
112
+ assert_equal 6765, @fibonacci.compute( 20 )
113
+ assert_equal 75_025, @fibonacci.compute( 25 )
114
+ assert_equal 9227465, @fibonacci.compute( 35 )
115
+ assert_equal 280571172992510140037611932413038677189525,
116
+ @fibonacci.compute( 200 )
117
+ assert_equal 176023680645013966468226945392411250770384383304492191886725992896575345044216019675,
118
+ @fibonacci.compute( 400 )
119
+ end
120
+ }
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,73 @@
1
+ module Dynamic
2
+ class << self
3
+ Thread.main[:DYNAMIC] = Hash.new { |hash, key|
4
+ raise NameError, "no such dynamic variable: #{key}"
5
+ }
6
+
7
+ def here!
8
+ Thread.current[:DYNAMIC] = Hash.new { |hash, key|
9
+ raise NameError, "no such dynamic variable: #{key}"
10
+ }.update Thread.main[:DYNAMIC]
11
+ end
12
+
13
+ def variables
14
+ Thread.current[:DYNAMIC] or here!
15
+ end
16
+
17
+ def variable(definition)
18
+ case definition
19
+ when Symbol
20
+ if variables.has_key? definition
21
+ raise NameError, "dynamic variable `#{definition}' already exists"
22
+ end
23
+ variables[definition] = nil
24
+ when Hash
25
+ definition.each { |key, value|
26
+ if variables.has_key? key
27
+ raise NameError, "dynamic variable `#{key}' already exists"
28
+ end
29
+ variables[key] = value
30
+ }
31
+ else
32
+ raise ArgumentError,
33
+ "can't create a new dynamic variable from #{definition.class}"
34
+ end
35
+ end
36
+
37
+ def [](key)
38
+ variables[key]
39
+ end
40
+
41
+ def []=(key, value)
42
+ variables[key] = value
43
+ end
44
+
45
+ def undefine(*keys)
46
+ keys.each { |key|
47
+ self[key]
48
+ variables.delete key
49
+ }
50
+ end
51
+
52
+ def let(bindings, &block)
53
+ save = {}
54
+ bindings.to_hash.collect { |key, value|
55
+ save[key] = self[key]
56
+ self[key] = value
57
+ }
58
+ return_value = block.call
59
+ variables.update save
60
+ return_value
61
+ end
62
+
63
+ def method_missing(name, *args)
64
+ if match = /=\Z/.match(name.to_s) # setter?
65
+ raise ArgumentError, "invalid setter call" unless args.size == 1
66
+ self[match.pre_match.intern] = args.first
67
+ else
68
+ raise ArgumentError, "invalid getter call" unless args.empty?
69
+ self[name]
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,17 @@
1
+ unless Object.const_defined? "MethodNatureSuperClass"
2
+ MethodNatureSuperClass = Struct.new(:arguments, :return_value, :break, :block)
3
+ end
4
+ class MethodNature < MethodNatureSuperClass
5
+ def break!( *value )
6
+ self.break = true
7
+ self.return_value = value.first unless value.empty?
8
+ end
9
+
10
+ def call_next
11
+ block.call( *arguments )
12
+ end
13
+
14
+ def call_next_with( *args )
15
+ block.call( *args )
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # TODO: get rid of this workaround to avoid double loading on `rake test`
2
+ unless Object.const_defined? "ContextR"
3
+ require 'rubygems'
4
+ require 'active_support'
5
+
6
+ Dir[File.join(File.dirname(__FILE__), '../ext/**/*.rb')].sort.each { |lib| require lib }
7
+ Dir[File.join(File.dirname(__FILE__), 'core_ext/**/*.rb')].sort.each { |lib| require lib }
8
+ Dir[File.join(File.dirname(__FILE__), 'contextr/**/*.rb')].sort.each { |lib| require lib }
9
+
10
+ end
11
+ unless Dynamic.variables.include?( :layers )
12
+ Dynamic.variable( :layers => [ ContextR::DefaultLayer ] )
13
+ end