contextr 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.
@@ -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