├── var ├── name ├── title ├── version ├── company ├── created ├── summary ├── authors ├── repositories ├── copyrights ├── requirements ├── description └── resources ├── lib ├── mirror.yml ├── mirror │ ├── class_mirror.rb │ ├── mirror.rb │ ├── module_mirror.rb │ └── instance_mirror.rb └── mirror.rb ├── Gemfile ├── demo ├── applique │ └── requires.rb ├── 03_instance_mirror.md ├── 02_mirror.md └── 01_overview.md ├── .gitignore ├── .yardopts ├── .travis.yml ├── HISTORY.md ├── Assembly ├── LICENSE.txt ├── .index ├── README.md └── .gemspec /var/name: -------------------------------------------------------------------------------- 1 | real 2 | -------------------------------------------------------------------------------- /var/title: -------------------------------------------------------------------------------- 1 | Real 2 | -------------------------------------------------------------------------------- /lib/mirror.yml: -------------------------------------------------------------------------------- 1 | ../.index -------------------------------------------------------------------------------- /var/version: -------------------------------------------------------------------------------- 1 | 0.1.0 2 | -------------------------------------------------------------------------------- /var/company: -------------------------------------------------------------------------------- 1 | Rubyworks 2 | -------------------------------------------------------------------------------- /var/created: -------------------------------------------------------------------------------- 1 | 2012-12-17 2 | -------------------------------------------------------------------------------- /var/summary: -------------------------------------------------------------------------------- 1 | Real Reflections on Ruby Object 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /demo/applique/requires.rb: -------------------------------------------------------------------------------- 1 | require 'ae' 2 | require 'mirror' 3 | -------------------------------------------------------------------------------- /var/authors: -------------------------------------------------------------------------------- 1 | --- 2 | - Thomas Sawyer 3 | 4 | -------------------------------------------------------------------------------- /var/repositories: -------------------------------------------------------------------------------- 1 | --- 2 | upstream: git://github.com/rubyworks/real.git 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .reap/digest 2 | .yardoc 3 | doc 4 | log 5 | pkg 6 | tmp 7 | web 8 | -------------------------------------------------------------------------------- /var/copyrights: -------------------------------------------------------------------------------- 1 | --- 2 | - (c) 2009 Thomas Sawyer, Rubyworks (BSD-2-Clause) 3 | 4 | -------------------------------------------------------------------------------- /var/requirements: -------------------------------------------------------------------------------- 1 | --- 2 | - detroit (build) 3 | - qed (test) 4 | - ae (test) 5 | 6 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --title "Real Reflection API" 2 | --protected 3 | --private 4 | lib/ 5 | - 6 | [A-Z]*.* 7 | 8 | -------------------------------------------------------------------------------- /lib/mirror/class_mirror.rb: -------------------------------------------------------------------------------- 1 | module Mirror 2 | 3 | # 4 | class ClassMirror < ModuleMirror 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /var/description: -------------------------------------------------------------------------------- 1 | Real makes true reflection possible for Ruby objects. 2 | This can be important to metaprogrammers who need to 3 | ensure they have the true information. 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | script: "bundle exec qed" 3 | rvm: 4 | - 1.8.7 5 | - 1.9.2 6 | - 1.9.3 7 | - rbx 8 | - rbx-19mode 9 | - jruby 10 | - jruby-19mode 11 | - ree 12 | -------------------------------------------------------------------------------- /demo/03_instance_mirror.md: -------------------------------------------------------------------------------- 1 | # InstanceMirror 2 | 3 | An InstanceMirror reflects on an object as an object. 4 | 5 | string = "something" 6 | 7 | Mirror[string].class #=> String 8 | 9 | -------------------------------------------------------------------------------- /var/resources: -------------------------------------------------------------------------------- 1 | --- 2 | home: http://rubyworks.github.com/real 3 | docs: http://rubydoc.info/gems/real 4 | code: http://github.com/rubyworks/real 5 | mail: http://groups.google.com/group/rubyworks-mailinglist 6 | 7 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # RELEASE HISTORY 2 | 3 | ## 0.1.0 / 2012-12-17 4 | 5 | First release of Real, a library to make object reflection dependable 6 | as is possiblein pure Ruby. 7 | 8 | Changes: 9 | 10 | * Happy Release Day!!! 11 | 12 | -------------------------------------------------------------------------------- /lib/mirror/mirror.rb: -------------------------------------------------------------------------------- 1 | module Mirror 2 | 3 | # Base class for all other mirror classes. 4 | class Mirror 5 | 6 | # B/c mirror's override #class. 7 | alias :object_class :class 8 | 9 | private 10 | 11 | def bind_call(c, m, *a, &b) 12 | im = c.instance_method(m) 13 | im.bind(@subject).call(*a, &b) 14 | end 15 | 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /demo/02_mirror.md: -------------------------------------------------------------------------------- 1 | # Mirror Module 2 | 3 | The toplevel Mirror module provides a single method `#[]` that is the 4 | primary interface. It is a factory methods and returns the coresponding 5 | mirror instance for a given object to be reflected upon. 6 | 7 | Mirror["string"].object_class #=> Mirror::InstanceMirror 8 | 9 | Mirror[String].object_class #=> Mirror::ClassMirror 10 | 11 | Mirror[Enumerable].object_class #=> Mirror::ModuleMirror 12 | 13 | 14 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | gem: 3 | gemspec: pkg/pic.gemspec 4 | active: true 5 | 6 | github: 7 | gh_pages: web 8 | 9 | dnote: 10 | title: Source Notes 11 | labels: ~ 12 | output: log/notes.html 13 | 14 | yard: 15 | active: false 16 | yardopts: true 17 | priority: 2 18 | 19 | qed: 20 | files: demo 21 | 22 | qedoc: 23 | title: Edited Pictures for Ruby 24 | files: demo 25 | output: DEMO.md 26 | 27 | vclog: 28 | output: 29 | - log/history.html 30 | - log/changes.html 31 | 32 | email: 33 | file: ~ 34 | subject: ~ 35 | mailto: 36 | - ruby-talk@ruby-lang.org 37 | - rubyworks-mailinglist@googlegroups.com 38 | #parts: [readme] 39 | 40 | -------------------------------------------------------------------------------- /lib/mirror.rb: -------------------------------------------------------------------------------- 1 | require 'mirror/mirror' 2 | require 'mirror/instance_mirror' 3 | require 'mirror/module_mirror' 4 | require 'mirror/class_mirror' 5 | 6 | module Mirror 7 | 8 | # 9 | # Access to project metadata, e.g. VERSION. 10 | # 11 | def self.const_missing(const_name) 12 | name = const_name.to_s.downcase 13 | index[name] || super(const_name) 14 | end 15 | 16 | # 17 | # Load project metadata file. 18 | # 19 | def self.index 20 | @index ||= ( 21 | require 'yaml' 22 | YAML.load_file(File.join(File.dirname(__FILE__), 'mirror.yml')) 23 | ) 24 | end 25 | 26 | # Factory method to get the coresponding mirror for the given 27 | # subject. 28 | # 29 | # @todo Add cache? 30 | # 31 | # @return [Mirror] 32 | def self.[](subject) 33 | case subject 34 | when Class 35 | ClassMirror.new(subject) 36 | when Module 37 | ModuleMirror.new(subject) 38 | else 39 | InstanceMirror.new(subject) 40 | end 41 | end 42 | 43 | end 44 | 45 | -------------------------------------------------------------------------------- /demo/01_overview.md: -------------------------------------------------------------------------------- 1 | # Mirror 2 | 3 | ## Overview 4 | 5 | There is a problem in the realm of Ruby metaprogramming: *objects can be liers*. 6 | You see, there is no guaruntee that the return value of a method is the "truth". 7 | Any object can play dirty tricks. 8 | 9 | string = "Watch this..." 10 | 11 | def string.class 12 | nil 13 | end 14 | 15 | string.class #=> nil 16 | 17 | We are never going to know what the *real* class of that object is by asking it. 18 | So what can we do? 19 | 20 | Ultimately the best solution is for Ruby itself to support explicit 21 | meta-programming methods. But since this is notforthcoming, there is 22 | luckily a trick we can use to provide endow a library with the ability. 23 | The trick to get an UnboundMethod from Object (or Module as the case 24 | may be), bind it to the object in question and then call it. In this way 25 | we route around any possible overrides (beyond Object itself, of course). 26 | 27 | method = String.instance_method(:class) 28 | method.bind(string).call #=> String 29 | 30 | So the Mirror library uses this trick throughout to provided *real* 31 | reflection on objects. 32 | 33 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD-2-Clause License 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY Thomas Sawyer ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Thomas Sawyer OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | -------------------------------------------------------------------------------- /lib/mirror/module_mirror.rb: -------------------------------------------------------------------------------- 1 | module Mirror 2 | 3 | # Reflect on an object instance. 4 | # 5 | class ModuleMirror < Mirror 6 | 7 | def initialize(subject) 8 | @subject = subject 9 | end 10 | 11 | # Get class/module's real instance methods. 12 | # 13 | # @return [Array] 14 | def instance_methods(*a, &b) 15 | bind_call(Module, :instanance_methods, *a, &b) 16 | end 17 | 18 | # Get class/module's real public instance methods. 19 | # 20 | # @return [Array] 21 | def public_instance_methods(*a, &b) 22 | bind_call(Module, :public_instance_methods, *a, &b) 23 | end 24 | 25 | # Get class/module's real protected instance methods. 26 | # 27 | # @return [Array] 28 | def protected_instance_methods(*a, &b) 29 | bind_call(Module, :protected_instance_methods, *a, &b) 30 | end 31 | 32 | # Get class/module's real private instance methods. 33 | # 34 | # @return [Array] 35 | def private_instance_methods(*a, &b) 36 | bind_call(Module, :private_instance_methods, :class, *a, &b) 37 | end 38 | 39 | # Get list class/module's constants. 40 | # 41 | # @return [Array] 42 | def constants(*a, &b) 43 | bind_call(Module, :constants, *a, &b) 44 | end 45 | 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | type: ruby 3 | revision: 2013 4 | sources: 5 | - var 6 | authors: 7 | - name: Thomas Sawyer 8 | email: transfire@gmail.com 9 | organizations: [] 10 | requirements: 11 | - groups: 12 | - build 13 | development: true 14 | name: detroit 15 | - groups: 16 | - test 17 | development: true 18 | name: qed 19 | - groups: 20 | - test 21 | development: true 22 | name: ae 23 | conflicts: [] 24 | alternatives: [] 25 | resources: 26 | - type: home 27 | uri: http://rubyworks.github.com/real 28 | label: Homepage 29 | - type: docs 30 | uri: http://rubydoc.info/gems/real 31 | label: Documentation 32 | - type: code 33 | uri: http://github.com/rubyworks/real 34 | label: Source Code 35 | - type: mail 36 | uri: http://groups.google.com/group/rubyworks-mailinglist 37 | label: Mailing List 38 | repositories: 39 | - name: upstream 40 | scm: git 41 | uri: git://github.com/rubyworks/real.git 42 | categories: [] 43 | load_path: 44 | - lib 45 | copyrights: 46 | - holder: Thomas Sawyer, Rubyworks 47 | year: '2009' 48 | license: BSD-2-Clause 49 | created: '2012-12-17' 50 | summary: Real Reflections on Ruby Object 51 | title: Real 52 | version: 0.1.0 53 | name: real 54 | description: ! "Real makes true reflection possible for Ruby objects.\nThis can be 55 | important to metaprogrammers who need to \nensure they have the true information." 56 | date: '2012-12-17' 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mirror 2 | 3 | [![Gem Version](https://badge.fury.io/rb/mirror.png)](http://badge.fury.io/rb/mirror) 4 | [![Build Status](https://secure.travis-ci.org/rubyworks/mirror.png)](http://travis-ci.org/rubyworks/mirror)     5 | [![Flattr Me](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/324911/Rubyworks-Ruby-Development-Fund) 6 | 7 | [Homepage](http://rubyworks.github.com/mirror) / 8 | [Documentation](http://rubydoc.info/gems/mirror) / 9 | [Support](http://github.com/rubyworks/mirror/issues) / 10 | [Source Code](http://github.com/rubyworks/mirror) 11 | 12 | 13 | There is a problem in the realm of Ruby metaprogramming" *objects can be liars*. 14 | You see, there is no guaruntee that the return value of a method is the "truth". 15 | Any object can play dirty tricks. 16 | 17 | string = "Watch this..." 18 | 19 | def string.class 20 | nil 21 | end 22 | 23 | string.class #=> nil 24 | 25 | We are never going to know what the *mirror* class of that object is 26 | by asking it. So what can we do? 27 | 28 | I've advocated for explict meta-programming methods be added to Ruby 29 | for a long time. So far to no avail. Finally, I've decided I could 30 | at least provide my own library that provides the functionality. 31 | 32 | require 'mirror' 33 | 34 | Mirror[string].class #=> String 35 | 36 | 37 | ### Installation 38 | 39 | Putting the old RubyGems to work: 40 | 41 | $ gem install mirror 42 | 43 | 44 | ### Copyrights 45 | 46 | Real is copyrighted open source software. 47 | 48 | Copyright (c) 2012 Rubyworks (BSD-2-Clause) 49 | 50 | You many redistribute or modify this work in accordance with the **BSD-2-Clause** license. 51 | 52 | See LICENSE.txt for details. 53 | -------------------------------------------------------------------------------- /lib/mirror/instance_mirror.rb: -------------------------------------------------------------------------------- 1 | module Mirror 2 | 3 | # Reflect on an object instance. 4 | # 5 | class InstanceMirror < Mirror 6 | 7 | def initialize(subject) 8 | @subject = subject 9 | end 10 | 11 | # Get instance's id. 12 | # 13 | # @return [Integer] 14 | def id(*a, &b) 15 | bind_call(Object, :object_id, *a, &b) 16 | end 17 | 18 | # Get instance's class. 19 | # 20 | # @return [Class] 21 | def class(*a, &b) 22 | bind_call(Object, :class, *a, &b) 23 | end 24 | 25 | # Get a list of the subject's instance variables. 26 | # 27 | # @return [Array] 28 | def variables 29 | bind_call(Object, :instance_variables) 30 | end 31 | 32 | # Get a instance's state in the form of a mapping of instance 33 | # variable name to instance variable value. 34 | # 35 | # @todo Array, Hash, etc have "hidden" state that ultimately 36 | # must be delt with specially. 37 | # 38 | # @return [Hash] 39 | def state 40 | s = {} 41 | variables.each do |v| 42 | s[v] = bind_call(Object, :instance_variable_get, v) 43 | end 44 | s 45 | end 46 | 47 | # Get instance variable value. 48 | # 49 | # @return [Object] 50 | def get(name) 51 | name = "@#{name}" unless name.to_s.start_with?('@') 52 | bind_call(Object, :instance_variable_get, name) 53 | end 54 | alias :[] :get 55 | 56 | # Set instance variable value. 57 | # 58 | # @return [Object] 59 | def set(name, value) 60 | name = "@#{name}" unless name.to_s.start_with?('@') 61 | bind_call(Object, :instance_variable_set, name, value) 62 | end 63 | alias :[]= :set 64 | 65 | # Get object's real methods. 66 | # 67 | # @return [Array] 68 | def methods(*a, &b) 69 | bind_call(Object, :methods, *a, &b) 70 | end 71 | 72 | # Get object's real public methods. 73 | # 74 | # @return [Array] 75 | def public_methods(*a, &b) 76 | bind_call(Object, :public_methods, *a, &b) 77 | end 78 | 79 | # Get object's real protected methods. 80 | # 81 | # @return [Array] 82 | def protected_methods(*a, &b) 83 | bind_call(Object, :protected_methods, *a, &b) 84 | end 85 | 86 | # Get object's real private methods. 87 | # 88 | # @return [Array] 89 | def private_methods(*a, &b) 90 | bind_call(Object, :private_methods, *a, &b) 91 | end 92 | 93 | end 94 | 95 | end 96 | -------------------------------------------------------------------------------- /.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | require 'pathname' 5 | 6 | module Indexer 7 | 8 | # Convert index data into a gemspec. 9 | # 10 | # Notes: 11 | # * Assumes all executables are in bin/. 12 | # * Does not yet handle default_executable setting. 13 | # * Does not yet handle platform setting. 14 | # * Does not yet handle required_ruby_version. 15 | # * Support for rdoc entries is weak. 16 | # 17 | class GemspecExporter 18 | 19 | # File globs to include in package --unless a manifest file exists. 20 | FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES) 21 | 22 | # File globs to omit from FILES. 23 | OMIT = "Config.rb" unless defined?(OMIT) 24 | 25 | # Standard file patterns. 26 | PATTERNS = { 27 | :root => '{.index,Gemfile}', 28 | :bin => 'bin/*', 29 | :lib => 'lib/{**/}*', #.rb', 30 | :ext => 'ext/{**/}extconf.rb', 31 | :doc => '*.{txt,rdoc,md,markdown,tt,textile}', 32 | :test => '{test,spec}/{**/}*.rb' 33 | } unless defined?(PATTERNS) 34 | 35 | # For which revision of indexer spec is this converter intended? 36 | REVISION = 2013 unless defined?(REVISION) 37 | 38 | # 39 | def self.gemspec 40 | new.to_gemspec 41 | end 42 | 43 | # 44 | attr :metadata 45 | 46 | # 47 | def initialize(metadata=nil) 48 | @root_check = false 49 | 50 | if metadata 51 | root_dir = metadata.delete(:root) 52 | if root_dir 53 | @root = root_dir 54 | @root_check = true 55 | end 56 | metadata = nil if metadata.empty? 57 | end 58 | 59 | @metadata = metadata || YAML.load_file(root + '.index') 60 | 61 | if @metadata['revision'].to_i != REVISION 62 | warn "This gemspec exporter was not designed for this revision of index metadata." 63 | end 64 | end 65 | 66 | # 67 | def has_root? 68 | root ? true : false 69 | end 70 | 71 | # 72 | def root 73 | return @root if @root || @root_check 74 | @root_check = true 75 | @root = find_root 76 | end 77 | 78 | # 79 | def manifest 80 | return nil unless root 81 | @manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first 82 | end 83 | 84 | # 85 | def scm 86 | return nil unless root 87 | @scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym 88 | end 89 | 90 | # 91 | def files 92 | return [] unless root 93 | @files ||= \ 94 | if manifest 95 | File.readlines(manifest). 96 | map{ |line| line.strip }. 97 | reject{ |line| line.empty? || line[0,1] == '#' } 98 | else 99 | list = [] 100 | Dir.chdir(root) do 101 | FILES.split(/\s+/).each do |pattern| 102 | list.concat(glob(pattern)) 103 | end 104 | OMIT.split(/\s+/).each do |pattern| 105 | list = list - glob(pattern) 106 | end 107 | end 108 | list 109 | end.select{ |path| File.file?(path) }.uniq 110 | end 111 | 112 | # 113 | def glob_files(pattern) 114 | return [] unless root 115 | Dir.chdir(root) do 116 | Dir.glob(pattern).select do |path| 117 | File.file?(path) && files.include?(path) 118 | end 119 | end 120 | end 121 | 122 | def patterns 123 | PATTERNS 124 | end 125 | 126 | def executables 127 | @executables ||= \ 128 | glob_files(patterns[:bin]).map do |path| 129 | File.basename(path) 130 | end 131 | end 132 | 133 | def extensions 134 | @extensions ||= \ 135 | glob_files(patterns[:ext]).map do |path| 136 | File.basename(path) 137 | end 138 | end 139 | 140 | def name 141 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 142 | end 143 | 144 | def homepage 145 | page = ( 146 | metadata['resources'].find{ |r| r['type'] =~ /^home/i } || 147 | metadata['resources'].find{ |r| r['name'] =~ /^home/i } || 148 | metadata['resources'].find{ |r| r['name'] =~ /^web/i } 149 | ) 150 | page ? page['uri'] : false 151 | end 152 | 153 | def licenses 154 | metadata['copyrights'].map{ |c| c['license'] }.compact 155 | end 156 | 157 | def require_paths 158 | metadata['load_path'] || ['lib'] 159 | end 160 | 161 | # 162 | # Convert to gemnspec. 163 | # 164 | def to_gemspec 165 | if has_root? 166 | Gem::Specification.new do |gemspec| 167 | to_gemspec_data(gemspec) 168 | to_gemspec_paths(gemspec) 169 | end 170 | else 171 | Gem::Specification.new do |gemspec| 172 | to_gemspec_data(gemspec) 173 | to_gemspec_paths(gemspec) 174 | end 175 | end 176 | end 177 | 178 | # 179 | # Convert pure data settings. 180 | # 181 | def to_gemspec_data(gemspec) 182 | gemspec.name = name 183 | gemspec.version = metadata['version'] 184 | gemspec.summary = metadata['summary'] 185 | gemspec.description = metadata['description'] 186 | 187 | metadata['authors'].each do |author| 188 | gemspec.authors << author['name'] 189 | 190 | if author.has_key?('email') 191 | if gemspec.email 192 | gemspec.email << author['email'] 193 | else 194 | gemspec.email = [author['email']] 195 | end 196 | end 197 | end 198 | 199 | gemspec.licenses = licenses 200 | 201 | requirements = metadata['requirements'] || [] 202 | requirements.each do |req| 203 | next if req['optional'] 204 | next if req['external'] 205 | 206 | name = req['name'] 207 | groups = req['groups'] || [] 208 | 209 | version = gemify_version(req['version']) 210 | 211 | if groups.empty? or groups.include?('runtime') 212 | # populate runtime dependencies 213 | if gemspec.respond_to?(:add_runtime_dependency) 214 | gemspec.add_runtime_dependency(name,*version) 215 | else 216 | gemspec.add_dependency(name,*version) 217 | end 218 | else 219 | # populate development dependencies 220 | if gemspec.respond_to?(:add_development_dependency) 221 | gemspec.add_development_dependency(name,*version) 222 | else 223 | gemspec.add_dependency(name,*version) 224 | end 225 | end 226 | end 227 | 228 | # convert external dependencies into gemspec requirements 229 | requirements.each do |req| 230 | next unless req['external'] 231 | gemspec.requirements << ("%s-%s" % req.values_at('name', 'version')) 232 | end 233 | 234 | gemspec.homepage = homepage 235 | gemspec.require_paths = require_paths 236 | gemspec.post_install_message = metadata['install_message'] 237 | end 238 | 239 | # 240 | # Set gemspec settings that require a root directory path. 241 | # 242 | def to_gemspec_paths(gemspec) 243 | gemspec.files = files 244 | gemspec.extensions = extensions 245 | gemspec.executables = executables 246 | 247 | if Gem::VERSION < '1.7.' 248 | gemspec.default_executable = gemspec.executables.first 249 | end 250 | 251 | gemspec.test_files = glob_files(patterns[:test]) 252 | 253 | unless gemspec.files.include?('.document') 254 | gemspec.extra_rdoc_files = glob_files(patterns[:doc]) 255 | end 256 | end 257 | 258 | # 259 | # Return a copy of this file. This is used to generate a local 260 | # .gemspec file that can automatically read the index file. 261 | # 262 | def self.source_code 263 | File.read(__FILE__) 264 | end 265 | 266 | private 267 | 268 | def find_root 269 | root_files = patterns[:root] 270 | if Dir.glob(root_files).first 271 | Pathname.new(Dir.pwd) 272 | elsif Dir.glob("../#{root_files}").first 273 | Pathname.new(Dir.pwd).parent 274 | else 275 | #raise "Can't find root of project containing `#{root_files}'." 276 | warn "Can't find root of project containing `#{root_files}'." 277 | nil 278 | end 279 | end 280 | 281 | def glob(pattern) 282 | if File.directory?(pattern) 283 | Dir.glob(File.join(pattern, '**', '*')) 284 | else 285 | Dir.glob(pattern) 286 | end 287 | end 288 | 289 | def gemify_version(version) 290 | case version 291 | when /^(.*?)\+$/ 292 | ">= #{$1}" 293 | when /^(.*?)\-$/ 294 | "< #{$1}" 295 | when /^(.*?)\~$/ 296 | "~> #{$1}" 297 | else 298 | version 299 | end 300 | end 301 | 302 | end 303 | 304 | end 305 | 306 | Indexer::GemspecExporter.gemspec --------------------------------------------------------------------------------