nyanko 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +25 -0
  4. data/MIT-LICENSE +22 -0
  5. data/README.md +105 -0
  6. data/Rakefile +1 -0
  7. data/lib/nyanko/active_if.rb +57 -0
  8. data/lib/nyanko/config.rb +13 -0
  9. data/lib/nyanko/controller.rb +23 -0
  10. data/lib/nyanko/function.rb +50 -0
  11. data/lib/nyanko/helper.rb +29 -0
  12. data/lib/nyanko/invoker/function_finder.rb +48 -0
  13. data/lib/nyanko/invoker/options.rb +69 -0
  14. data/lib/nyanko/invoker.rb +68 -0
  15. data/lib/nyanko/loader.rb +59 -0
  16. data/lib/nyanko/railtie.rb +13 -0
  17. data/lib/nyanko/unit/extender/active_record_class_methods.rb +56 -0
  18. data/lib/nyanko/unit/extender/extension.rb +51 -0
  19. data/lib/nyanko/unit/extender.rb +21 -0
  20. data/lib/nyanko/unit/scope_finder.rb +41 -0
  21. data/lib/nyanko/unit.rb +86 -0
  22. data/lib/nyanko/unit_proxy.rb +30 -0
  23. data/lib/nyanko/unit_proxy_provider.rb +21 -0
  24. data/lib/nyanko/version.rb +3 -0
  25. data/lib/nyanko.rb +16 -0
  26. data/nyanko.gemspec +29 -0
  27. data/spec/dummy/README.rdoc +261 -0
  28. data/spec/dummy/Rakefile +7 -0
  29. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  30. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  31. data/spec/dummy/app/assets/stylesheets/main.scss +21 -0
  32. data/spec/dummy/app/assets/stylesheets/reset.scss +14 -0
  33. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  34. data/spec/dummy/app/controllers/entries_controller.rb +33 -0
  35. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  36. data/spec/dummy/app/mailers/.gitkeep +0 -0
  37. data/spec/dummy/app/models/.gitkeep +0 -0
  38. data/spec/dummy/app/models/entry.rb +3 -0
  39. data/spec/dummy/app/units/entry_deletion/entry_deletion.rb +37 -0
  40. data/spec/dummy/app/units/entry_deletion/views/_delete_link.html.slim +1 -0
  41. data/spec/dummy/app/views/entries/edit.html.slim +14 -0
  42. data/spec/dummy/app/views/entries/index.html.slim +5 -0
  43. data/spec/dummy/app/views/entries/show.html.slim +8 -0
  44. data/spec/dummy/app/views/layouts/application.html.slim +16 -0
  45. data/spec/dummy/config/application.rb +68 -0
  46. data/spec/dummy/config/boot.rb +10 -0
  47. data/spec/dummy/config/database.yml +25 -0
  48. data/spec/dummy/config/environment.rb +5 -0
  49. data/spec/dummy/config/environments/development.rb +37 -0
  50. data/spec/dummy/config/environments/production.rb +67 -0
  51. data/spec/dummy/config/environments/test.rb +37 -0
  52. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  53. data/spec/dummy/config/initializers/inflections.rb +15 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  55. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  56. data/spec/dummy/config/initializers/session_store.rb +8 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +5 -0
  59. data/spec/dummy/config/routes.rb +5 -0
  60. data/spec/dummy/config.ru +4 -0
  61. data/spec/dummy/db/migrate/20130127170331_create_entries.rb +11 -0
  62. data/spec/dummy/db/schema.rb +24 -0
  63. data/spec/dummy/lib/assets/.gitkeep +0 -0
  64. data/spec/dummy/log/.gitkeep +0 -0
  65. data/spec/dummy/public/404.html +26 -0
  66. data/spec/dummy/public/422.html +26 -0
  67. data/spec/dummy/public/500.html +25 -0
  68. data/spec/dummy/public/favicon.ico +0 -0
  69. data/spec/dummy/script/rails +6 -0
  70. data/spec/fixtures/units/example_unit/example_unit.rb +53 -0
  71. data/spec/fixtures/units/inactive_unit/inactive_unit.rb +11 -0
  72. data/spec/nyanko/controller_spec.rb +39 -0
  73. data/spec/nyanko/function_spec.rb +40 -0
  74. data/spec/nyanko/helper_spec.rb +26 -0
  75. data/spec/nyanko/invoker_spec.rb +116 -0
  76. data/spec/nyanko/loader_spec.rb +43 -0
  77. data/spec/nyanko/unit/extender_spec.rb +40 -0
  78. data/spec/nyanko/unit/scope_finder_spec.rb +37 -0
  79. data/spec/nyanko/unit_proxy_provider_spec.rb +40 -0
  80. data/spec/nyanko/unit_proxy_spec.rb +23 -0
  81. data/spec/nyanko/unit_spec.rb +169 -0
  82. data/spec/spec_helper.rb +21 -0
  83. metadata +320 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: 3bf6a9e3b51bc80536b6dd54ca34a36cce8bde19
4
+ data.tar.gz: ee455931da637b0687a514b177bdbcb42a43c1b1
5
+ !binary "U0hBNTEy":
6
+ metadata.gz: 49253ba6ec4aa0195957714b64ab93802ed1727c3af38a90b2c7bf003f861517209261f2e1c9a0a8b3d9e5b39191fe09d526bc4d03ce9cc0696db4180ac9a3dd
7
+ data.tar.gz: 29bb6270a940e5a74208536928f58c547c9b4fa042f69135e92a672b2dbf6b4458de9f388d7feaa58dbef81340c686131dddfe9096a8735ae63d0f2fa2598041
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ log/*.log
2
+ spec/dummy/db/*.sqlite3
3
+ spec/dummy/log/*.log
4
+ spec/dummy/tmp/
5
+ spec/dummy/.sass-cache
6
+ *.gem
7
+ *.rbc
8
+ .bundle
9
+ .config
10
+ .yardoc
11
+ Gemfile.lock
12
+ InstalledFiles
13
+ _yardoc
14
+ coverage
15
+ doc/
16
+ lib/bundler/man
17
+ pkg
18
+ rdoc
19
+ spec/reports
20
+ test/tmp
21
+ test/version_tmp
22
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,25 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test, :production do
6
+ gem "jquery-rails"
7
+ gem "quiet_assets"
8
+ gem "rails", ">= 3.0.10"
9
+ gem "slim"
10
+ gem "sqlite3"
11
+ end
12
+
13
+ group :test do
14
+ gem "rspec-rails", "2.12.2"
15
+ end
16
+
17
+ group :development, :test do
18
+ gem "pry-rails"
19
+ end
20
+
21
+ group :assets do
22
+ gem "sass-rails", ">= 3.0.10"
23
+ gem "coffee-rails", ">= 3.0.10"
24
+ gem "uglifier"
25
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ryo Nakamura
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Nyanko
2
+ Nyanko is a Rails extension tool.
3
+ This is deeply inspired from [Chanko](https://github.com/cookpad/chanko) and has same API as Chanko.
4
+
5
+ ![](http://octodex.github.com/images/nyantocat.gif)
6
+
7
+
8
+ ## Requirements
9
+ * Ruby >= 1.8.7
10
+ * Rails >= 3.0.10
11
+
12
+
13
+ ## Install
14
+ ```
15
+ $ gem install nyanko
16
+ ```
17
+
18
+
19
+ ## Usage
20
+
21
+ ### Gemfile
22
+ ```ruby
23
+ # Gemfile
24
+ gem "nyanko"
25
+ ```
26
+
27
+ ### Invoke
28
+ ```ruby
29
+ class EntriesController < ApplicationController
30
+ unit_action :entry_deletion, :destroy
31
+
32
+ def index
33
+ invoke(:entry_deletion, :index) do
34
+ @entries = Entry.all
35
+ end
36
+ end
37
+ end
38
+ ```
39
+
40
+ ### Unit
41
+ ```ruby
42
+ # app/units/entry_deletion/entry_deletion.rb
43
+ module EntryDeletion
44
+ include Nyanko::Unit
45
+
46
+ active_if { Rails.env.development? }
47
+
48
+ scope(:view) do
49
+ function(:delete_link) do
50
+ render "/delete_link", :entry => entry if entry.persisted?
51
+ end
52
+ end
53
+
54
+ scope(:controller) do
55
+ function(:destroy) do
56
+ entry = Entry.find(params[:id])
57
+ entry.unit.soft_delete
58
+ redirect_to entries_path
59
+ end
60
+
61
+ function(:index) do
62
+ @entries = Entry.unit.active
63
+ end
64
+ end
65
+
66
+ models do
67
+ expand(:Entry) do
68
+ scope :active, lambda { where(:deleted_at => nil) }
69
+
70
+ def soft_delete
71
+ update_attributes(:deleted_at => Time.now)
72
+ end
73
+ end
74
+ end
75
+
76
+ helpers do
77
+ def link_to_deletion(entry)
78
+ link_to "Delete", entry, :method => :delete
79
+ end
80
+ end
81
+ end
82
+ ```
83
+
84
+ ```
85
+ -# app/units/entry_deletion/views/_delete_link.html.slim
86
+ = unit.link_to_deletion(entry)
87
+ ```
88
+
89
+
90
+ ## Example App
91
+ There is an example rails application for Nyanko in spec/dummy directory.
92
+ ```
93
+ $ git clone git@github.com:r7kamura/nyanko.git
94
+ $ cd nyanko/spec/dummy
95
+ $ rails s
96
+ ```
97
+
98
+
99
+ ## Todo
100
+ * auto-reloading
101
+ * logger
102
+ * configuration
103
+ * backwoard compatibility (alias ext to unit)
104
+ * document
105
+ * test (for now, test coverage is 100%)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,57 @@
1
+ module Nyanko
2
+ class ActiveIf
3
+ class << self
4
+ def define(label, &block)
5
+ definitions[label] = block
6
+ end
7
+
8
+ def find(label)
9
+ definitions[label]
10
+ end
11
+
12
+ def definitions
13
+ @definitions ||= {}
14
+ end
15
+
16
+ def clear
17
+ definitions.clear
18
+ end
19
+ end
20
+
21
+ def initialize(*conditions, &block)
22
+ @options = conditions.extract_options!
23
+ @conditions = conditions
24
+ @block = block
25
+ end
26
+
27
+ def active?(context, options = {})
28
+ blocks.all? {|block| block.call(context, options) }
29
+ end
30
+
31
+ def blocks
32
+ @blocks ||= begin
33
+ @conditions.map do |condition|
34
+ condition.is_a?(Any) ? condition.to_block : self.class.find(condition)
35
+ end << @block
36
+ end.compact
37
+ end
38
+
39
+ class Any
40
+ def initialize(*labels)
41
+ @labels = labels
42
+ end
43
+
44
+ def to_block
45
+ proc do |context, options|
46
+ definitions.any? do |definition|
47
+ definition.call(context, options)
48
+ end
49
+ end
50
+ end
51
+
52
+ def definitions
53
+ @labels.map {|label| ActiveIf.find(label) }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ module Nyanko
2
+ module Config
3
+ class << self
4
+ def units_directory_path
5
+ @units_directory_path ||= "app/units"
6
+ end
7
+
8
+ def units_directory_path=(path)
9
+ @units_directory_path = path
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module Nyanko
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Invoker
7
+ end
8
+
9
+ module ClassMethods
10
+ private
11
+
12
+ def unit_action(unit_name, *function_names, &block)
13
+ options = function_names.extract_options!
14
+ block ||= Proc.new { head 400 }
15
+ Array.wrap(function_names).each do |function_name|
16
+ define_method(function_name) do
17
+ invoke(unit_name, function_name, options, &block)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,50 @@
1
+ module Nyanko
2
+ class Function
3
+ attr_reader :block, :unit, :label
4
+
5
+ class << self
6
+ def units
7
+ @units ||= []
8
+ end
9
+
10
+ def current_unit
11
+ units.last
12
+ end
13
+ end
14
+
15
+ def initialize(unit, label, &block)
16
+ @unit = unit
17
+ @label = label
18
+ @block = block
19
+ end
20
+
21
+ def invoke(context, options = {})
22
+ with_unit_stack(context) do
23
+ with_unit_view_path(context) do
24
+ context.instance_eval(&block)
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def with_unit_stack(context)
32
+ context.units << @unit
33
+ self.class.units << @unit
34
+ yield
35
+ ensure
36
+ self.class.units.pop
37
+ context.units.pop
38
+ end
39
+
40
+ def with_unit_view_path(context)
41
+ if context.view?
42
+ origin = context.view_paths
43
+ context.view_paths.unshift unit.view_path
44
+ end
45
+ yield
46
+ ensure
47
+ context.view_paths = origin if context.view?
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ module Nyanko
2
+ module Helper
3
+ class << self
4
+ def define(class_name, &block)
5
+ prefix = UnitProxy.generate_prefix(class_name)
6
+ define_methods_with_prefix(prefix, &block)
7
+ end
8
+
9
+ def define_methods_with_prefix(prefix, &block)
10
+ define_methods(&block).each do |name|
11
+ change_method_name(name, "#{prefix}#{name}")
12
+ end
13
+ end
14
+
15
+ def define_methods(&block)
16
+ before = instance_methods(false)
17
+ self.class_eval(&block)
18
+ instance_methods(false) - before
19
+ end
20
+
21
+ def change_method_name(from, to)
22
+ class_eval do
23
+ alias_method to, from
24
+ remove_method from
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ module Nyanko
2
+ module Invoker
3
+ class FunctionFinder
4
+ UnitNotFound = Class.new(StandardError)
5
+ FunctionNotFound = Class.new(StandardError)
6
+
7
+ def self.find(*args)
8
+ new(*args).find or raise FunctionNotFound
9
+ end
10
+
11
+ def initialize(context, options)
12
+ @context = context
13
+ @options = options
14
+ end
15
+
16
+ def find
17
+ @options[:functions].find do |unit_name, label|
18
+ unit = find_unit(unit_name)
19
+ identifier = @options[:as] || @context.class
20
+ next unless unit.active?(@context, @options[:active_if_options])
21
+ function = unit.find_function(identifier, label)
22
+ break function if function
23
+ end
24
+ end
25
+
26
+ def find_with_dependencies
27
+ find_without_dependencies unless has_inactive_dependent_unit?
28
+ end
29
+ alias_method_chain :find, :dependencies
30
+
31
+ def find_unit(name)
32
+ Loader.load(name) or raise UnitNotFound
33
+ end
34
+
35
+ def has_inactive_dependent_unit?
36
+ dependent_units.any? {|unit| !unit.active?(@context, @options[:active_if_options]) }
37
+ end
38
+
39
+ def dependent_units
40
+ dependent_unit_names.map {|name| find_unit(name) }
41
+ end
42
+
43
+ def dependent_unit_names
44
+ Array.wrap(@options[:dependencies])
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,69 @@
1
+ module Nyanko
2
+ module Invoker
3
+ class Options
4
+ CANDIDATES = {
5
+ :active_if_options => true,
6
+ :as => true,
7
+ :capture => true,
8
+ :if => true,
9
+ :locals => true,
10
+ :type => true,
11
+ }
12
+
13
+ def initialize(*args)
14
+ @raw_options = args.extract_options!
15
+ @args = args
16
+ end
17
+
18
+ def [](key)
19
+ send(key)
20
+ end
21
+
22
+ def functions
23
+ @args.first.is_a?(Array) ? @args : [[@args[0], @args[1]]]
24
+ end
25
+
26
+ def locals
27
+ (options[:locals] || {}).symbolize_keys
28
+ end
29
+
30
+ def active_if_options
31
+ options[:active_if_options] || {}
32
+ end
33
+
34
+ def as
35
+ options[:as]
36
+ end
37
+
38
+ def dependencies
39
+ options[:if]
40
+ end
41
+
42
+ def capture
43
+ options.has_key?(:capture) ? capture[:capture] : true
44
+ end
45
+
46
+ def type
47
+ options[:type]
48
+ end
49
+
50
+ def invoke_options
51
+ { :capture => capture, :type => type }
52
+ end
53
+
54
+ def options
55
+ @options ||= begin
56
+ if short_hand_options?
57
+ { :locals => @raw_options }
58
+ else
59
+ @raw_options
60
+ end
61
+ end
62
+ end
63
+
64
+ def short_hand_options?
65
+ @raw_options.any? && @raw_options.keys.all? {|key| !CANDIDATES[key] }
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,68 @@
1
+ require "nyanko/invoker/options"
2
+ require "nyanko/invoker/function_finder"
3
+
4
+ module Nyanko
5
+ module Invoker
6
+ def invoke(*args, &block)
7
+ options = Options.new(*args)
8
+ unit_locals_stack << options.locals
9
+ function = FunctionFinder.find(self, options)
10
+ result = function.invoke(self, options.invoke_options)
11
+ result = surround_with_html_tag(result, function, options) if view?
12
+ result
13
+ rescue Exception
14
+ p $!
15
+ case
16
+ when !block
17
+ nil
18
+ when view?
19
+ capture(&block)
20
+ else
21
+ instance_exec(&block)
22
+ end
23
+ ensure
24
+ unit_locals_stack.pop
25
+ end
26
+
27
+ def units
28
+ @units ||= []
29
+ end
30
+
31
+ def view?
32
+ is_a?(ActionView::Base)
33
+ end
34
+
35
+ private
36
+
37
+ # Search shared method or locals variable
38
+ def method_missing(method_name, *args, &block)
39
+ if (methods = units.last.try(:shared_methods)) && block = methods[method_name]
40
+ self.instance_exec(*args, &block)
41
+ elsif args.empty? && value = (unit_locals_stack.last || {})[method_name]
42
+ value
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ def unit_locals_stack
49
+ @unit_locals_stack ||= []
50
+ end
51
+
52
+ def surround_with_html_tag(str, function, options)
53
+ classes = %W[
54
+ unit
55
+ unit__#{function.unit.name.underscore}
56
+ unit__#{function.unit.name.underscore}__#{function.label}
57
+ ]
58
+ case options.type
59
+ when :plain
60
+ str
61
+ when :inline
62
+ content_tag(:span, str, :class => classes)
63
+ else
64
+ content_tag(:div, str, :class => classes)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,59 @@
1
+ require "pathname"
2
+
3
+ module Nyanko
4
+ class Loader
5
+ class << self
6
+ def load(unit_name)
7
+ new(unit_name).load
8
+ end
9
+
10
+ def cache
11
+ @cache ||= {}
12
+ end
13
+ end
14
+
15
+ def initialize(name)
16
+ @name = name
17
+ end
18
+
19
+ def load
20
+ loaded? ? load_from_cache : load_from_file
21
+ end
22
+
23
+ def loaded?
24
+ cache[@name] != nil
25
+ end
26
+
27
+ def load_from_cache
28
+ cache[@name]
29
+ end
30
+
31
+ def load_from_file
32
+ require_unit_files
33
+ cache[@name] = constantize
34
+ rescue Exception
35
+ cache[@name] = false
36
+ nil
37
+ end
38
+
39
+ def require_unit_files
40
+ paths.each {|path| require Rails.root.join(path) }
41
+ end
42
+
43
+ def paths
44
+ Pathname.glob("#{directory_path}/#@name/#@name.rb").sort
45
+ end
46
+
47
+ def directory_path
48
+ Config.units_directory_path
49
+ end
50
+
51
+ def constantize
52
+ @name.to_s.camelize.constantize
53
+ end
54
+
55
+ def cache
56
+ self.class.cache
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ require "rails"
2
+
3
+ module Nyanko
4
+ class Railtie < Rails::Railtie
5
+ initializer "nyanko" do |app|
6
+ ::ActionView::Base.send(:include, Invoker, Helper, UnitProxyProvider)
7
+ ::ActionController::Base.send(:include, Controller)
8
+ ::ActiveRecord::Base.send(:include, UnitProxyProvider)
9
+ ::ActiveRecord::Relation.send(:include, UnitProxyProvider)
10
+ ::ActiveRecord::Associations::CollectionAssociation.send(:include, UnitProxyProvider)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ module Nyanko
2
+ module Unit
3
+ class Extender
4
+ module ActiveRecordClassMethods
5
+ delegate(
6
+ :apply_modules,
7
+ :arel,
8
+ :array_of_strings?,
9
+ :build_arel,
10
+ :build_joins,
11
+ :build_select,
12
+ :build_where,
13
+ :create_with,
14
+ :custom_join_sql,
15
+ :eager_load,
16
+ :extending,
17
+ :from,
18
+ :group,
19
+ :having,
20
+ :includes,
21
+ :joins,
22
+ :limit,
23
+ :lock,
24
+ :offset,
25
+ :order,
26
+ :preload,
27
+ :readonly,
28
+ :reorder,
29
+ :reverse_order,
30
+ :reverse_sql_order,
31
+ :scope,
32
+ :select,
33
+ :where,
34
+ :to => :@mod
35
+ )
36
+
37
+ %w[belongs_to has_many has_one].each do |method_name|
38
+ class_eval <<-EOS
39
+ def #{method_name}(*args, &block)
40
+ name = @prefix + args.shift.to_s
41
+ options = args.extract_options!
42
+ options = options.reverse_merge(:class_name => @mod.to_s)
43
+ args << options
44
+ @mod.#{method_name}(name.to_sym, *args, &block)
45
+ end
46
+ EOS
47
+ end
48
+
49
+ def scope(*args, &block)
50
+ name = @prefix + args.shift.to_s
51
+ @mod.scope(name, *args)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end