magnetic 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,31 @@
1
+
2
+ lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
3
+
4
+ require 'rubygems'
5
+
6
+ Gem::Specification::new do |spec|
7
+ $VERBOSE = nil
8
+ spec.name = lib
9
+ spec.version = version
10
+ spec.platform = Gem::Platform::RUBY
11
+ spec.summary = lib
12
+
13
+ spec.files = Dir::glob "**/**"
14
+ spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
15
+
16
+ spec.require_path = "lib"
17
+ spec.autorequire = lib
18
+
19
+ spec.has_rdoc = File::exist? "doc"
20
+ spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
21
+ spec.add_dependency 'pervasives', '~> 1.0'
22
+ spec.add_dependency 'arrayfields', '~> 3.7'
23
+ spec.add_dependency 'attributes', '~> 3.3'
24
+ spec.add_dependency 'prototype', '~> 2.0'
25
+
26
+ spec.extensions << "extconf.rb" if File::exists? "extconf.rb"
27
+
28
+ spec.author = "Ara T. Howard"
29
+ spec.email = "ara.t.howard@gmail.com"
30
+ spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
31
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # built-in
3
+ #
4
+ require 'pathname'
5
+ require 'fileutils'
6
+ #
7
+ # gems
8
+ #
9
+ require 'rubygems'
10
+ require 'pervasives'
11
+ require 'arrayfields'
12
+ require 'attributes'
13
+ require 'prototype'
14
+ #
15
+ # magnetic
16
+ #
17
+ require 'magnetic/binding_of_caller'
18
+ require 'magnetic/rubyext'
19
+ require 'magnetic/field'
20
+ require 'magnetic/interface'
21
+ require 'magnetic/rails'
@@ -0,0 +1,84 @@
1
+ begin
2
+ require 'simplecc'
3
+ rescue LoadError
4
+ class Continuation # :nodoc: # for RDoc
5
+ end
6
+ def Continuation.create(*args, &block) # :nodoc:
7
+ cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
8
+ result ||= args
9
+ return *[cc, *result]
10
+ end
11
+ end
12
+
13
+ class Binding; end # for RDoc
14
+ # This method returns the binding of the method that called your
15
+ # method. It will raise an Exception when you're not inside a method.
16
+ #
17
+ # It's used like this:
18
+ # def inc_counter(amount = 1)
19
+ # Binding.of_caller do |binding|
20
+ # # Create a lambda that will increase the variable 'counter'
21
+ # # in the caller of this method when called.
22
+ # inc = eval("lambda { |arg| counter += arg }", binding)
23
+ # # We can refer to amount from inside this block safely.
24
+ # inc.call(amount)
25
+ # end
26
+ # # No other statements can go here. Put them inside the block.
27
+ # end
28
+ # counter = 0
29
+ # 2.times { inc_counter }
30
+ # counter # => 2
31
+ #
32
+ # Binding.of_caller must be the last statement in the method.
33
+ # This means that you will have to put everything you want to
34
+ # do after the call to Binding.of_caller into the block of it.
35
+ # This should be no problem however, because Ruby has closures.
36
+ # If you don't do this an Exception will be raised. Because of
37
+ # the way that Binding.of_caller is implemented it has to be
38
+ # done this way.
39
+ def Binding.of_caller(&block)
40
+ old_critical = Thread.critical
41
+ Thread.critical = true
42
+ count = 0
43
+ cc, result, error, extra_data = Continuation.create(nil, nil)
44
+ error.call if error
45
+
46
+ tracer = lambda do |*args|
47
+ type, context, extra_data = args[0], args[4], args
48
+ if type == "return"
49
+ count += 1
50
+ # First this method and then calling one will return --
51
+ # the trace event of the second event gets the context
52
+ # of the method which called the method that called this
53
+ # method.
54
+ if count == 2
55
+ # It would be nice if we could restore the trace_func
56
+ # that was set before we swapped in our own one, but
57
+ # this is impossible without overloading set_trace_func
58
+ # in current Ruby.
59
+ set_trace_func(nil)
60
+ cc.call(eval("binding", context), nil, extra_data)
61
+ end
62
+ elsif type == "line" then
63
+ nil
64
+ elsif type == "c-return" and extra_data[3] == :set_trace_func then
65
+ nil
66
+ else
67
+ set_trace_func(nil)
68
+ error_msg = "Binding.of_caller used in non-method context or " +
69
+ "trailing statements of method using it aren't in the block."
70
+ cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
71
+ end
72
+ end
73
+
74
+ unless result
75
+ set_trace_func(tracer)
76
+ return nil
77
+ else
78
+ Thread.critical = old_critical
79
+ case block.arity
80
+ when 1 then yield(result)
81
+ else yield(result, extra_data)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,227 @@
1
+ module Magnetic
2
+ module Field
3
+ Base = Object.prototype do
4
+ name nil
5
+ owner nil
6
+ #controller nil
7
+ model nil
8
+ #interface nil
9
+ #records nil
10
+ value nil
11
+ #path nil
12
+ type :html
13
+
14
+ def __
15
+ @__ ||= Pervasives::Proxy.new(self)
16
+ end
17
+
18
+ def to_s
19
+ value.to_s
20
+ end
21
+
22
+ attribute('template_root'){ File.join RAILS_ROOT, 'app', 'views', 'magnetic' }
23
+ attribute('template_dir'){ File.join template_root, File.join(*owner.name.gsub(%r/^:+/,'').split(%r/::/)).downcase }
24
+ attribute('template_base'){ name }
25
+ #attribute('template_ext'){ type.to_s }
26
+ attribute('template_prefix'){ File.join(template_dir, template_base) }
27
+ attribute('template_inline'){ send "template_inline_#{ type }" }
28
+ attribute('template_text'){ nil }
29
+ attribute('template_map'){ { 'html' => 'rhtml', 'xml' => 'rxml' } }
30
+
31
+ #
32
+ # TODO - this needs to be thought out further
33
+ #
34
+ def render *argv
35
+ raise 'recursive render!' if defined?(@inside_render) and @inside_render
36
+ @inside_render = true
37
+ begin
38
+ field = self
39
+
40
+ type = argv.delete_first{|arg| String === arg or Symbol === arg } || self.type
41
+ type = type.to_s
42
+
43
+ options = argv.delete_first{|arg| Hash === arg} || {}
44
+ options.to_options!
45
+
46
+ msg = options.delete(:render) || :render_to_string
47
+
48
+ text = options[:text] || template_text rescue nil
49
+ inline = options[:inline] || template_inline rescue nil
50
+
51
+ unless text or inline
52
+ file = options[:file]
53
+ unless file
54
+ ext = (template_map[type] || type).gsub %r/^\.?/, '.'
55
+ options[:file] = template_prefix + ext
56
+ end
57
+ end
58
+
59
+ controller.clone.instance_eval do
60
+ @field = field
61
+ (options[:locals] ||= {}).update :field => @field
62
+ send msg, options
63
+ end
64
+ ensure
65
+ @inside_render = false
66
+ end
67
+ end
68
+
69
+ def configure options = {}, &block
70
+ options.to_options!
71
+ prototyping do
72
+ options.each do |k,v|
73
+ begin
74
+ __send__ "#{ k }=", v
75
+ rescue
76
+ __attribute__ k => v
77
+ end
78
+ end
79
+ end
80
+ prototyping &block
81
+ self
82
+ end
83
+ alias_method 'configured', 'configure'
84
+
85
+ def to_proc
86
+ @to_proc ||= lambda do |options|
87
+ options.to_options!
88
+ field = self
89
+ value = options[:value]
90
+ unless value.nil?
91
+ sc =
92
+ class << value
93
+ self
94
+ end
95
+ sc.module_eval do
96
+ define_method :field do
97
+ field.configure options
98
+ field
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+ def to_proc
107
+ @to_proc ||= lambda do |options|
108
+ field = self
109
+ field_options = options.to_options
110
+ value = options[:value]
111
+ raise ArgumentError, "no value in <#{ options.inspect }>" unless value
112
+ value.extend ConfiguredFieldMethod
113
+ value.field = field
114
+ value.field_options = field_options
115
+ end
116
+ end
117
+
118
+ module ConfiguredFieldMethod
119
+ attr_writer 'field'
120
+ attr_writer 'field_options'
121
+
122
+ def field
123
+ @field_options.each do |k, v|
124
+ unless @field.respond_to? k
125
+ sc =
126
+ class << @field
127
+ self
128
+ end
129
+ sc.module_eval{ attribute k }
130
+ end
131
+ @field.send "#{ k }=", v
132
+ end
133
+ @field
134
+ end
135
+ end
136
+
137
+ def === other
138
+ Base.class === other
139
+ end
140
+ end
141
+
142
+ ### TODO try not to use array fields here
143
+ class Set < ::Array
144
+ include Fieldable
145
+ class << self
146
+ def [] *a, &b
147
+ a = super
148
+ ensure
149
+ a.fields = []
150
+ end
151
+ end
152
+ def initialize *a, &b
153
+ super
154
+ ensure
155
+ self.fields = []
156
+ end
157
+ end
158
+
159
+ module DSL
160
+ def fieldset
161
+ @fieldset ||= Field::Set[]
162
+ end
163
+ def field *argv, &block
164
+ name = argv.delete_first{|arg| String === arg or Symbol === arg }
165
+ base = argv.delete_first{|arg| Field::Base.class === arg}
166
+ configuring = argv.delete_first{|arg| ['configure', :configure, 'configuring', :configuring].include? arg}
167
+ options = argv.delete_first{|arg| Hash === arg}
168
+
169
+ name ||= base.name
170
+ raise ArgumentError, 'nameless field!' unless name
171
+ name = name.to_s
172
+
173
+ if options.nil? and base.nil? and block.nil?
174
+ field = field_for name
175
+ field.clone unless field.nil?
176
+ else
177
+ options ||= {}
178
+ options.to_options!
179
+ field =
180
+ if configuring
181
+ field_for name
182
+ else
183
+ base ||= Field::Base
184
+ field = base.clone
185
+ field.name = name
186
+ field.owner = self
187
+ field
188
+ end
189
+
190
+ field.configure options, &block
191
+
192
+ #p [ (field.owner.name rescue field.owner.class.name), field.name, (configuring ? :configuring : false), caller.first ]
193
+
194
+ unless configuring
195
+ raise ArgumentError, "duplicate field '#{ name }' in #{ fieldset[name].inspect }" if fieldset.has_key?(field.name)
196
+ fieldset[field.name] = field
197
+ end
198
+
199
+ field
200
+ end
201
+ end
202
+ def field_for name
203
+ fieldset[name.to_s]
204
+ end
205
+ def self.included other
206
+ super
207
+ ensure
208
+ other.extend self
209
+ end
210
+ end
211
+ end
212
+
213
+ def self.field *argv, &block
214
+ name = argv.delete_first{|arg| String === arg or Symbol === arg }
215
+ base = argv.delete_first{|arg| Field::Base.class === arg}
216
+ configure = argv.delete_first{|arg| ['configure', :configure].include? arg}
217
+ options = argv.delete_first{|arg| Hash === arg}
218
+ options ||= {}
219
+ options.to_options!
220
+ base ||= Field::Base
221
+ field = base.clone
222
+ field.name = name
223
+ field.owner = self
224
+ field.configure options, &block
225
+ field
226
+ end
227
+ end
@@ -0,0 +1,99 @@
1
+ module Magnetic
2
+ class Path < ::String; end
3
+ def self.path(*a, &b) a.size == 0 ? Path : Path.new(*a, &b) end
4
+
5
+ class Interface
6
+ include Magnetic::Field::DSL
7
+
8
+ attribute 'records'
9
+ attribute 'mapping'
10
+
11
+ def initialize options = {}, &block
12
+ options.to_options!
13
+ records = options[:records]
14
+ controller = options[:controller]
15
+ @records = (( Array === records and ActiveRecord::Base === records[0] )) ? records : [records]
16
+ @records = [] if records.nil?
17
+ @controller = controller
18
+ @mapping = []
19
+ instance_eval &block if block
20
+ post_initialize
21
+ end
22
+
23
+ def map mapping
24
+ mapping.each do |key, value|
25
+ key = key.to_s
26
+ raise ArgumentError, 'empty key!' if key.empty?
27
+ raise ArgumentError, 'no value!' if value.nil?
28
+ @mapping << [key, value]
29
+ if Magnetic::Field::Base === value
30
+ field(value) unless field(value.name)
31
+ end
32
+ end
33
+ end
34
+
35
+ def post_initialize
36
+ map!
37
+ end
38
+
39
+ def map!
40
+ @records.each{|record| map_record :record => record, :mapping => @mapping} unless @mapping.empty?
41
+ end
42
+
43
+ def map_record options = {}
44
+ options.to_options!
45
+
46
+ record = options.delete :record
47
+ mapping = options.delete :mapping
48
+ route = options.delete :route
49
+
50
+ table_name = record.class.table_name
51
+ id = record.id
52
+
53
+ (( route ||= [] )) << "#{ table_name }[#{ id }]"
54
+
55
+ mapping.each do |path, block|
56
+ head, *tail = path.split '.'
57
+ m, head, array, *ignored = %r/^(.*?)(\[\*?\])?$/o.match(head).to_a
58
+
59
+ if array
60
+ subrecords = record.send head
61
+ subrecords = [subrecords] unless subrecords.class == Array
62
+ subpath = tail.join '.'
63
+ subblock = block
64
+ submapping = [[ subpath, subblock ]]
65
+ subrecords.each do |subrecord|
66
+ subroute = route.clone
67
+ map_record :record => subrecord, :mapping => submapping, :route => subroute
68
+ end
69
+ else
70
+ value = record.send head
71
+ path = Magnetic.path(( [route, head].join('.') ))
72
+ block.to_proc.call :path => path,
73
+ :value => value,
74
+ :model => record.class,
75
+ :table_name => table_name,
76
+ :column_name => head,
77
+ :record => record,
78
+ :interface => self,
79
+ :controller => @controller
80
+ end
81
+ end
82
+ end
83
+
84
+ module DSL
85
+ def interface *a, &b
86
+ if a.empty? and b.nil?
87
+ @interface
88
+ else
89
+ @interface = Interface.new :records => a.shift, :controller => self, &b
90
+ end
91
+ end
92
+ def self.included other
93
+ super
94
+ ensure
95
+ other.extend self
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,32 @@
1
+ if defined? Rails or defined? RAILS
2
+ class ActiveRecord::Base
3
+ include Magnetic::Field::DSL
4
+
5
+ def self.field_for name
6
+ name = name.to_s
7
+ fieldset[name] or generate_default_field_for(name)
8
+ end
9
+
10
+ def self.generate_default_field_for name
11
+ cname = name.to_s
12
+ m = self
13
+ raise ArgumentError, "no such column <#{ cname }>" unless columns_hash[cname]
14
+ field cname do
15
+ model m
16
+ end
17
+ end
18
+ end
19
+
20
+ if defined? ActionController
21
+ class ActionController::Base
22
+ include Magnetic::Interface::DSL
23
+ end
24
+ end
25
+
26
+ unless defined? ApplicationController
27
+ class ApplicationController < ActionController::Base; end
28
+ end
29
+ class ApplicationController
30
+ include Magnetic::Interface::DSL
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ class Object
2
+ def higherself
3
+ Binding.of_caller{|binding| eval 'self', binding}
4
+ end
5
+ end
6
+ class Hash
7
+ unless instance_methods.include? 'to_options'
8
+ def to_options
9
+ keys.inject({}){|h,k| h.update k.to_s.to_sym => self[k]}
10
+ end
11
+ end
12
+ unless instance_methods.include? 'to_options!'
13
+ def to_options!
14
+ replace to_options
15
+ end
16
+ end
17
+ end
18
+ class Array
19
+ def delete_first *argv, &block
20
+ match = block ? block : lambda{|arg| argv.first == arg}
21
+ at = nil
22
+ each_with_index do |element, index|
23
+ if match[element]
24
+ at = index
25
+ break
26
+ end
27
+ end
28
+ at ? delete_at(at) : nil
29
+ end
30
+ end
File without changes
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: magnetic
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-06-04 00:00:00 -06:00
8
+ summary: magnetic
9
+ require_paths:
10
+ - lib
11
+ email: ara.t.howard@gmail.com
12
+ homepage: http://codeforpeople.com/lib/ruby/magnetic/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: magnetic
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Ara T. Howard
31
+ files:
32
+ - gemspec.rb
33
+ - lib
34
+ - lib/magnetic
35
+ - lib/magnetic/binding_of_caller.rb
36
+ - lib/magnetic/field.rb
37
+ - lib/magnetic/interface.rb
38
+ - lib/magnetic/rails.rb
39
+ - lib/magnetic/rubyext.rb
40
+ - lib/magnetic.rb
41
+ - magnetic-0.0.1.gem
42
+ test_files: []
43
+
44
+ rdoc_options: []
45
+
46
+ extra_rdoc_files: []
47
+
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ requirements: []
53
+
54
+ dependencies:
55
+ - !ruby/object:Gem::Dependency
56
+ name: pervasives
57
+ version_requirement:
58
+ version_requirements: !ruby/object:Gem::Version::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: "1.0"
63
+ version:
64
+ - !ruby/object:Gem::Dependency
65
+ name: arrayfields
66
+ version_requirement:
67
+ version_requirements: !ruby/object:Gem::Version::Requirement
68
+ requirements:
69
+ - - ~>
70
+ - !ruby/object:Gem::Version
71
+ version: "3.7"
72
+ version:
73
+ - !ruby/object:Gem::Dependency
74
+ name: attributes
75
+ version_requirement:
76
+ version_requirements: !ruby/object:Gem::Version::Requirement
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: "3.3"
81
+ version:
82
+ - !ruby/object:Gem::Dependency
83
+ name: prototype
84
+ version_requirement:
85
+ version_requirements: !ruby/object:Gem::Version::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: "2.0"
90
+ version: