spiderfw 0.6.23 → 0.6.24
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.
- data/CHANGELOG +10 -1
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/apps/config_editor/_init.rb +1 -2
- data/apps/config_editor/controllers/config_editor_controller.rb +1 -7
- data/apps/core/admin/controllers/admin_controller.rb +1 -1
- data/apps/core/admin/public/css/sass/admin.css +35 -31
- data/apps/core/admin/public/sass/admin.scss +6 -1
- data/apps/core/components/widgets/crud/crud.shtml +2 -2
- data/apps/core/components/widgets/table/table.rb +5 -5
- data/apps/core/forms/tags/element_row.erb +15 -10
- data/apps/core/forms/widgets/form/form.rb +35 -22
- data/apps/core/forms/widgets/inputs/checkbox/checkbox.shtml +2 -2
- data/apps/core/forms/widgets/inputs/date_time/date_time.shtml +2 -2
- data/apps/core/forms/widgets/inputs/file_input/file_input.shtml +2 -2
- data/apps/core/forms/widgets/inputs/html_area/html_area.shtml +2 -2
- data/apps/core/forms/widgets/inputs/input/input.shtml +2 -2
- data/apps/core/forms/widgets/inputs/password/password.shtml +2 -2
- data/apps/core/forms/widgets/inputs/search_select/search_select.shtml +1 -1
- data/apps/core/forms/widgets/inputs/select/select.shtml +2 -2
- data/apps/core/forms/widgets/inputs/text/text.shtml +2 -2
- data/apps/core/forms/widgets/inputs/text_area/text_area.shtml +2 -2
- data/apps/core/forms/widgets/inputs/time_span/time_span.shtml +1 -1
- data/blueprints/home/config.ru +8 -0
- data/lib/spiderfw/app.rb +416 -224
- data/lib/spiderfw/cmd/commands/app.rb +243 -239
- data/lib/spiderfw/cmd/commands/cert.rb +421 -417
- data/lib/spiderfw/cmd/commands/config.rb +85 -82
- data/lib/spiderfw/cmd/commands/console.rb +64 -40
- data/lib/spiderfw/cmd/commands/content.rb +29 -25
- data/lib/spiderfw/cmd/commands/create.rb +58 -54
- data/lib/spiderfw/cmd/commands/model.rb +118 -114
- data/lib/spiderfw/cmd/commands/setup.rb +55 -51
- data/lib/spiderfw/cmd/commands/test.rb +63 -59
- data/lib/spiderfw/cmd/commands/webserver.rb +56 -51
- data/lib/spiderfw/config/options/spider.rb +4 -3
- data/lib/spiderfw/controller/controller.rb +2 -0
- data/lib/spiderfw/controller/http_controller.rb +1 -2
- data/lib/spiderfw/controller/mixins/static_content.rb +3 -3
- data/lib/spiderfw/controller/mixins/visual.rb +30 -15
- data/lib/spiderfw/controller/response.rb +84 -0
- data/lib/spiderfw/controller/session/file_session.rb +2 -2
- data/lib/spiderfw/http/adapters/rack.rb +12 -13
- data/lib/spiderfw/http/server.rb +80 -46
- data/lib/spiderfw/i18n/cldr.rb +6 -9
- data/lib/spiderfw/model/base_model.rb +103 -23
- data/lib/spiderfw/model/condition.rb +110 -25
- data/lib/spiderfw/model/mappers/db_mapper.rb +14 -6
- data/lib/spiderfw/model/mappers/mapper.rb +440 -197
- data/lib/spiderfw/model/model.rb +105 -21
- data/lib/spiderfw/model/model_hash.rb +9 -1
- data/lib/spiderfw/model/query.rb +50 -9
- data/lib/spiderfw/model/query_set.rb +211 -44
- data/lib/spiderfw/model/request.rb +28 -21
- data/lib/spiderfw/model/storage/base_storage.rb +125 -10
- data/lib/spiderfw/model/storage/db/db_storage.rb +7 -4
- data/lib/spiderfw/model/storage.rb +8 -1
- data/lib/spiderfw/setup/spider_setup_wizard.rb +9 -7
- data/lib/spiderfw/spider.rb +270 -43
- data/lib/spiderfw/templates/layout.rb +9 -4
- data/lib/spiderfw/templates/resources/sass.rb +3 -2
- data/lib/spiderfw/templates/template.rb +1 -0
- data/lib/spiderfw/utils/annotations.rb +3 -1
- data/lib/spiderfw/utils/logger.rb +1 -1
- data/lib/spiderfw/utils/monkey/symbol.rb +4 -2
- data/lib/spiderfw/utils/shared_store/file_shared_store.rb +2 -2
- data/lib/spiderfw/utils/thread_out.rb +3 -1
- data/public/css/error_page.css +83 -0
- data/public/js/error_page.js +5 -0
- data/spider.gemspec +4 -1
- data/templates/email/error.erb +9 -0
- metadata +28 -12
- data/apps/config_editor/widgets/edit_bool/edit_bool.rb +0 -8
- data/apps/config_editor/widgets/edit_bool/edit_bool.shtml +0 -5
    
        data/lib/spiderfw/app.rb
    CHANGED
    
    | @@ -3,249 +3,391 @@ require 'tsort' | |
| 3 3 |  | 
| 4 4 | 
             
            module Spider
         | 
| 5 5 |  | 
| 6 | 
            +
                # The Spider::App module must be included in each apps' main module inside the
         | 
| 7 | 
            +
                # apps's _init.rb file.
         | 
| 8 | 
            +
                # 
         | 
| 9 | 
            +
                # Example: apps/my_app/_init.rb
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                #   module MyApp
         | 
| 12 | 
            +
                #       include Spider::App
         | 
| 13 | 
            +
                #   end
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # It extends the including module, defining several variables and Class methods.
         | 
| 16 | 
            +
                # All variables are pre-set to defaults, but can be overridden by the including Module
         | 
| 17 | 
            +
                # (see {ClassMethods}).
         | 
| 18 | 
            +
                # 
         | 
| 19 | 
            +
                # The app's module can implement several lifecycle hooks (as Module methods):
         | 
| 20 | 
            +
                # * app_init: called during the framework's init phase
         | 
| 21 | 
            +
                # * app_startup: called when a server is started
         | 
| 22 | 
            +
                # * app_shutdown: called when a server is shut down
         | 
| 6 23 | 
             
                module App
         | 
| 7 24 |  | 
| 8 | 
            -
                     | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 25 | 
            +
                    # Methods set on the App main module.
         | 
| 26 | 
            +
                    # All instance attributes will be set to default values, but can be overridden
         | 
| 27 | 
            +
                    # by the module by setting the corresponding instance variable.
         | 
| 28 | 
            +
                    # Example:
         | 
| 29 | 
            +
                    # 
         | 
| 30 | 
            +
                    #   module MyApp
         | 
| 31 | 
            +
                    #       include Spider::App
         | 
| 32 | 
            +
                    #       @controller = :MyController
         | 
| 33 | 
            +
                    #       @label = 'My Application'
         | 
| 34 | 
            +
                    #   end
         | 
| 35 | 
            +
                    # 
         | 
| 36 | 
            +
                    module ClassMethods
         | 
| 37 | 
            +
                        
         | 
| 38 | 
            +
                        # @return [String] unique identifier for the app
         | 
| 39 | 
            +
                        attr_reader :id
         | 
| 40 | 
            +
                        # @return [String] filesystem path of the app
         | 
| 41 | 
            +
                        attr_reader :path
         | 
| 42 | 
            +
                        # @return [String] path of the 'public' folder
         | 
| 43 | 
            +
                        attr_reader :pub_path
         | 
| 44 | 
            +
                        # @return [String] path of the 'test' folder
         | 
| 45 | 
            +
                        attr_reader :test_path
         | 
| 46 | 
            +
                        # @return [String] path of the 'setup' folder
         | 
| 47 | 
            +
                        attr_reader :setup_path
         | 
| 48 | 
            +
                        # @return [String] path of the 'widgets' folder
         | 
| 49 | 
            +
                        attr_reader :widgets_path
         | 
| 50 | 
            +
                        # @return [String] path of the 'views' folder
         | 
| 51 | 
            +
                        attr_reader :views_path
         | 
| 52 | 
            +
                        # @return [String] path of the 'tags' folder
         | 
| 53 | 
            +
                        attr_reader :tags_path
         | 
| 54 | 
            +
                        # @return [String] path of the 'models' folder
         | 
| 55 | 
            +
                        attr_reader :models_path
         | 
| 56 | 
            +
                        # @return [String] name, without spaces
         | 
| 57 | 
            +
                        attr_reader :short_name
         | 
| 58 | 
            +
                        # @return [String] url from which the app will be routed
         | 
| 59 | 
            +
                        attr_reader :route_url
         | 
| 60 | 
            +
                        # @return [String] app
         | 
| 61 | 
            +
                        attr_reader :label
         | 
| 62 | 
            +
                        # @return [Gem::Version] app's version
         | 
| 63 | 
            +
                        attr_reader :version
         | 
| 64 | 
            +
                        # @return [String] prefix used to distinguish Database table
         | 
| 65 | 
            +
                        attr_accessor :short_prefix
         | 
| 66 | 
            +
                        # @return [AppSpec] the app's AppSpec
         | 
| 67 | 
            +
                        attr_reader :spec
         | 
| 68 | 
            +
                        # @return [Array] A list of directories to look for translations
         | 
| 69 | 
            +
                        attr_reader :gettext_dirs
         | 
| 70 | 
            +
                        # @return [Array] File extensions to parse for translations
         | 
| 71 | 
            +
                        attr_reader :gettext_extensions
         | 
| 72 | 
            +
                        # @return [Array] Additional GetText parasers to use
         | 
| 73 | 
            +
                        attr_reader :gettext_parsers
         | 
| 74 | 
            +
                        
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                        # Initializes missing variables to default variables.
         | 
| 77 | 
            +
                        def init
         | 
| 78 | 
            +
                            unless @path
         | 
| 79 | 
            +
                                file = caller[1].split(':')[0]
         | 
| 80 | 
            +
                                dir = File.dirname(file)
         | 
| 81 | 
            +
                                @path = dir
         | 
| 82 | 
            +
                            end
         | 
| 83 | 
            +
                            @path = File.expand_path(@path)
         | 
| 84 | 
            +
                            @short_name ||= Inflector.underscore(self.name).gsub(File::SEPARATOR, '_')
         | 
| 85 | 
            +
                            @dotted_name = Inflector.underscore(self.name).gsub(File::SEPARATOR, '.')
         | 
| 86 | 
            +
                            @pub_path ||= File.join(@path, 'public')
         | 
| 87 | 
            +
                            @test_path ||= File.join(@path, 'test')
         | 
| 88 | 
            +
                            @setup_path ||= File.join(@path, 'setup')
         | 
| 89 | 
            +
                            @models_path ||= File.join(@path, 'models')
         | 
| 90 | 
            +
                            @widgets_path ||= File.join(@path, 'widgets')
         | 
| 91 | 
            +
                            @views_path ||= File.join(@path, '/views')
         | 
| 92 | 
            +
                            @tags_path ||= File.join(@path, 'tags')
         | 
| 93 | 
            +
                            @version = Gem::Version.new(@version.to_s) if @version && !@version.is_a?(Gem::Version)
         | 
| 94 | 
            +
                            spec_path = File.join(@path, "#{@short_name}.appspec")
         | 
| 95 | 
            +
                            load_spec(spec_path) if File.exists?(spec_path)
         | 
| 96 | 
            +
                            @route_url ||= Inflector.underscore(self.name)
         | 
| 97 | 
            +
                            @label ||= @short_name.split('_').each{ |p| p[0] = p[0].chr.upcase }.join(' ')
         | 
| 98 | 
            +
                            @gettext_parsers ||= []
         | 
| 99 | 
            +
                            @gettext_dirs ||= ['lib','bin','controllers','models','views','widgets','public']
         | 
| 100 | 
            +
                            @gettext_extensions ||= ['rb','rhtml','shtml','js']
         | 
| 12 101 |  | 
| 13 | 
            -
                             | 
| 14 | 
            -
             | 
| 15 | 
            -
                                attr_reader :short_name, :route_url, :label, :version
         | 
| 16 | 
            -
                                attr_accessor :short_prefix
         | 
| 17 | 
            -
                                attr_reader :command
         | 
| 18 | 
            -
                                attr_reader :spec
         | 
| 19 | 
            -
                                attr_reader :gettext_dirs, :gettext_extensions, :gettext_parsers
         | 
| 20 | 
            -
                                
         | 
| 21 | 
            -
                                def init
         | 
| 22 | 
            -
                                    unless @path
         | 
| 23 | 
            -
                                        file = caller[1].split(':')[0]
         | 
| 24 | 
            -
                                        dir = File.dirname(file)
         | 
| 25 | 
            -
                                        @path = dir
         | 
| 26 | 
            -
                                    end
         | 
| 27 | 
            -
                                    @path = File.expand_path(@path)
         | 
| 28 | 
            -
                                    @short_name ||= Inflector.underscore(self.name).gsub(File::SEPARATOR, '_')
         | 
| 29 | 
            -
                                    @dotted_name = Inflector.underscore(self.name).gsub(File::SEPARATOR, '.')
         | 
| 30 | 
            -
                                    @pub_path ||= File.join(@path, 'public')
         | 
| 31 | 
            -
                                    @test_path ||= File.join(@path, 'test')
         | 
| 32 | 
            -
                                    @setup_path ||= File.join(@path, 'setup')
         | 
| 33 | 
            -
                                    @models_path ||= File.join(@path, 'models')
         | 
| 34 | 
            -
                                    @widgets_path ||= File.join(@path, 'widgets')
         | 
| 35 | 
            -
                                    @views_path ||= File.join(@path, '/views')
         | 
| 36 | 
            -
                                    @tags_path ||= File.join(@path, 'tags')
         | 
| 37 | 
            -
                                    @version = Gem::Version.new(@version.to_s) if @version && !@version.is_a?(Gem::Version)
         | 
| 38 | 
            -
                                    spec_path = File.join(@path, "#{@short_name}.appspec")
         | 
| 39 | 
            -
                                    load_spec(spec_path) if File.exists?(spec_path)
         | 
| 40 | 
            -
                                    @route_url ||= Inflector.underscore(self.name)
         | 
| 41 | 
            -
                                    @label ||= @short_name.split('_').each{ |p| p[0] = p[0].chr.upcase }.join(' ')
         | 
| 42 | 
            -
                                    @gettext_parsers ||= []
         | 
| 43 | 
            -
                                    @gettext_dirs ||= ['lib','bin','controllers','models','views','widgets','public']
         | 
| 44 | 
            -
                                    @gettext_extensions ||= ['rb','rhtml','shtml','js']
         | 
| 45 | 
            -
                                    
         | 
| 46 | 
            -
                                    find_tags
         | 
| 47 | 
            -
                                end
         | 
| 102 | 
            +
                            find_tags
         | 
| 103 | 
            +
                        end
         | 
| 48 104 |  | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 105 | 
            +
                        # @return [String] The apps' full_name or spec.name
         | 
| 106 | 
            +
                        def full_name
         | 
| 107 | 
            +
                            @full_name || self.spec.name
         | 
| 108 | 
            +
                        end
         | 
| 52 109 |  | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
                                     | 
| 74 | 
            -
                                    return nil unless Spider.site
         | 
| 75 | 
            -
                                    u = "http://#{Spider.site.domain}"
         | 
| 76 | 
            -
                                    u += ":#{Spider.site.port}" unless Spider.site.port == 80
         | 
| 77 | 
            -
                                    u += url
         | 
| 78 | 
            -
                                    u += "/"+action.to_s if action
         | 
| 79 | 
            -
                                    u
         | 
| 80 | 
            -
                                end
         | 
| 81 | 
            -
                                
         | 
| 82 | 
            -
                                def https_url
         | 
| 83 | 
            -
                                    return nil unless Spider.site && Spider.site.ssl?
         | 
| 84 | 
            -
                                    u = "https://#{Spider.site.domain}"
         | 
| 85 | 
            -
                                    u += ":#{Spider.site.ssl_port}" unless Spider.site.ssl_port == 443
         | 
| 86 | 
            -
                                    u += url
         | 
| 87 | 
            -
                                    u
         | 
| 88 | 
            -
                                end
         | 
| 89 | 
            -
                                
         | 
| 90 | 
            -
                                def http_s_url
         | 
| 91 | 
            -
                                    return https_url if Spider.site && Spider.site.ssl?
         | 
| 92 | 
            -
                                    return http_url
         | 
| 93 | 
            -
                                end
         | 
| 94 | 
            -
                                
         | 
| 95 | 
            -
                                def pub_url
         | 
| 96 | 
            -
                                    if Spider.conf.get('static_content.mode') == 'publish'
         | 
| 97 | 
            -
                                        Spider::HomeController.pub_url+'/apps/'+self.short_name
         | 
| 98 | 
            -
                                    else
         | 
| 99 | 
            -
                                        request_url+'/public'
         | 
| 100 | 
            -
                                    end
         | 
| 101 | 
            -
                                end
         | 
| 102 | 
            -
                                
         | 
| 103 | 
            -
                                def pub_url!
         | 
| 104 | 
            -
                                    request_url+'/public'
         | 
| 105 | 
            -
                                end
         | 
| 106 | 
            -
                                
         | 
| 107 | 
            -
                                def controller
         | 
| 108 | 
            -
                                    #controllers = self.const_get(:Controllers)
         | 
| 109 | 
            -
                                    if (!@controller || !const_defined?(@controller))
         | 
| 110 | 
            -
                                        @controller = :AppController
         | 
| 111 | 
            -
                                        return const_set(@controller, Spider::PageController.clone)
         | 
| 112 | 
            -
                                        
         | 
| 113 | 
            -
                                    end
         | 
| 114 | 
            -
                                    return const_get(@controller)
         | 
| 115 | 
            -
                                end
         | 
| 116 | 
            -
                                
         | 
| 117 | 
            -
                                def models(container=nil)
         | 
| 118 | 
            -
                                    container ||= self
         | 
| 119 | 
            -
                                    mods = []
         | 
| 120 | 
            -
                                    container.constants.each do |c|
         | 
| 121 | 
            -
                                        begin
         | 
| 122 | 
            -
                                            mods += get_models(container.const_get(c))
         | 
| 123 | 
            -
                                        rescue LoadError
         | 
| 124 | 
            -
                                        end
         | 
| 125 | 
            -
                                    end
         | 
| 126 | 
            -
                                    return mods
         | 
| 127 | 
            -
                                end
         | 
| 128 | 
            -
                                
         | 
| 129 | 
            -
                                def get_models(m)
         | 
| 130 | 
            -
                                    ms = []
         | 
| 131 | 
            -
                                    if m.respond_to?(:subclass_of?) && m.subclass_of?(Spider::Model::BaseModel)
         | 
| 132 | 
            -
                                         ms << m
         | 
| 133 | 
            -
                                         m.constants.each do |c|
         | 
| 134 | 
            -
                                             sub_mod = m.const_get(c)
         | 
| 135 | 
            -
                                             next unless sub_mod.is_a?(Module)
         | 
| 136 | 
            -
                                             next if !sub_mod.subclass_of?(Spider::Model::BaseModel) || sub_mod.app != self
         | 
| 137 | 
            -
                                             next if sub_mod == m
         | 
| 138 | 
            -
                                             ms += get_models(sub_mod)
         | 
| 139 | 
            -
                                         end
         | 
| 140 | 
            -
                                     elsif (m.is_a?(Module) && !m.is_a?(Class))
         | 
| 141 | 
            -
                                         return models(m)
         | 
| 142 | 
            -
                                     end
         | 
| 143 | 
            -
                                     return ms
         | 
| 144 | 
            -
                                end
         | 
| 145 | 
            -
                                
         | 
| 146 | 
            -
                                def controllers
         | 
| 147 | 
            -
                                    self.constants.map{ |m| const_get(m) }.select{ |m| m.subclass_of? Spider::Controller }
         | 
| 110 | 
            +
                        # @return [String] description or spec.description or name
         | 
| 111 | 
            +
                        def description
         | 
| 112 | 
            +
                            desc = @description || self.spec.description
         | 
| 113 | 
            +
                            desc.blank? ? self.name : desc
         | 
| 114 | 
            +
                        end
         | 
| 115 | 
            +
                        
         | 
| 116 | 
            +
                        # @return [String] The path used to access the application from the browser
         | 
| 117 | 
            +
                        def request_url
         | 
| 118 | 
            +
                            if u = Spider.conf.get("#{@dotted_name}.url") 
         | 
| 119 | 
            +
                                return u
         | 
| 120 | 
            +
                            end
         | 
| 121 | 
            +
                            Spider::ControllerMixins::HTTPMixin.reverse_proxy_mapping('/'+@route_url)
         | 
| 122 | 
            +
                        end
         | 
| 123 | 
            +
                        alias :url :request_url
         | 
| 124 | 
            +
                        
         | 
| 125 | 
            +
                        # @return [String] The full url used to access the application from the browser
         | 
| 126 | 
            +
                        def http_url(action=nil)
         | 
| 127 | 
            +
                            if u = Spider.conf.get("#{@dotted_name}.http_url") 
         | 
| 128 | 
            +
                                if action
         | 
| 129 | 
            +
                                    u += '/' if u[-1].chr != '/'
         | 
| 130 | 
            +
                                    u += action.to_s
         | 
| 148 131 | 
             
                                end
         | 
| 132 | 
            +
                                return u 
         | 
| 133 | 
            +
                            end
         | 
| 134 | 
            +
                            return nil unless Spider.site
         | 
| 135 | 
            +
                            u = "http://#{Spider.site.domain}"
         | 
| 136 | 
            +
                            u += ":#{Spider.site.port}" unless Spider.site.port == 80
         | 
| 137 | 
            +
                            u += url
         | 
| 138 | 
            +
                            u += "/"+action.to_s if action
         | 
| 139 | 
            +
                            u
         | 
| 140 | 
            +
                        end
         | 
| 141 | 
            +
                        
         | 
| 142 | 
            +
                        # The full url used to access the application from the browser, prefixed
         | 
| 143 | 
            +
                        # with https
         | 
| 144 | 
            +
                        # @return [String] 
         | 
| 145 | 
            +
                        def https_url
         | 
| 146 | 
            +
                            return nil unless Spider.site && Spider.site.ssl?
         | 
| 147 | 
            +
                            u = "https://#{Spider.site.domain}"
         | 
| 148 | 
            +
                            u += ":#{Spider.site.ssl_port}" unless Spider.site.ssl_port == 443
         | 
| 149 | 
            +
                            u += url
         | 
| 150 | 
            +
                            u
         | 
| 151 | 
            +
                        end
         | 
| 152 | 
            +
                        
         | 
| 153 | 
            +
                        # @return [String] If the site supports SSL, returns the #https_url; otherwise, the #http_url
         | 
| 154 | 
            +
                        def http_s_url
         | 
| 155 | 
            +
                            return https_url if Spider.site && Spider.site.ssl?
         | 
| 156 | 
            +
                            return http_url
         | 
| 157 | 
            +
                        end
         | 
| 158 | 
            +
                        
         | 
| 159 | 
            +
                        # @return [String] The url to the app's public content. If the static_content.mode configuration
         | 
| 160 | 
            +
                        # option is set to 'publish', the app's url inside the home is returned.
         | 
| 161 | 
            +
                        def pub_url
         | 
| 162 | 
            +
                            if Spider.conf.get('static_content.mode') == 'publish'
         | 
| 163 | 
            +
                                Spider::HomeController.pub_url+'/apps/'+self.short_name
         | 
| 164 | 
            +
                            else
         | 
| 165 | 
            +
                                request_url+'/public'
         | 
| 166 | 
            +
                            end
         | 
| 167 | 
            +
                        end
         | 
| 168 | 
            +
                        
         | 
| 169 | 
            +
                        # @return [String] The url to the app's public content, inside the app's folder (ignoring publishing mode)
         | 
| 170 | 
            +
                        def pub_url!
         | 
| 171 | 
            +
                            request_url+'/public'
         | 
| 172 | 
            +
                        end
         | 
| 173 | 
            +
                        
         | 
| 174 | 
            +
                        # @return [Spider::Controller] The apps' main Controller. 
         | 
| 175 | 
            +
                        # If setting the instance variable, use a Symbol
         | 
| 176 | 
            +
                        def controller
         | 
| 177 | 
            +
                            if (!@controller || !const_defined?(@controller))
         | 
| 178 | 
            +
                                @controller = :AppController
         | 
| 179 | 
            +
                                return const_set(@controller, Spider::PageController.clone)
         | 
| 149 180 |  | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 181 | 
            +
                            end
         | 
| 182 | 
            +
                            return const_get(@controller)
         | 
| 183 | 
            +
                        end
         | 
| 184 | 
            +
                        
         | 
| 185 | 
            +
                        # @return [Array] An array of all the {BaseModel} subclasses defined inside the module
         | 
| 186 | 
            +
                        def models(container=nil)
         | 
| 187 | 
            +
                            container ||= self
         | 
| 188 | 
            +
                            mods = []
         | 
| 189 | 
            +
                            container.constants.each do |c|
         | 
| 190 | 
            +
                                begin
         | 
| 191 | 
            +
                                    mods += get_models(container.const_get(c))
         | 
| 192 | 
            +
                                rescue LoadError
         | 
| 152 193 | 
             
                                end
         | 
| 194 | 
            +
                            end
         | 
| 195 | 
            +
                            return mods
         | 
| 196 | 
            +
                        end
         | 
| 197 | 
            +
                        
         | 
| 198 | 
            +
                        # @return [Array] An array of all the {Controller} subclasses defined inside the module
         | 
| 199 | 
            +
                        def controllers
         | 
| 200 | 
            +
                            self.constants.map{ |m| const_get(m) }.select{ |m| m.subclass_of? Spider::Controller }
         | 
| 201 | 
            +
                        end
         | 
| 202 | 
            +
                        
         | 
| 203 | 
            +
                        # Finds a resource (see {Spider.find_resource})
         | 
| 204 | 
            +
                        # @return [Spider::Resource]
         | 
| 205 | 
            +
                        def find_resource(type, name, cur_path=nil)
         | 
| 206 | 
            +
                            Spider.find_resource(type, name, cur_path, self)
         | 
| 207 | 
            +
                        end
         | 
| 153 208 |  | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
                                 | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
                                    self.controller.route(path, dest, options)
         | 
| 176 | 
            -
                                end
         | 
| 177 | 
            -
                                
         | 
| 178 | 
            -
                                def relative_path
         | 
| 179 | 
            -
                                    if Spider.paths[:apps] && @path.index(Spider.paths[:apps]) == 0
         | 
| 180 | 
            -
                                        return @path[Spider.paths[:apps].length+1..-1]
         | 
| 181 | 
            -
                                    else
         | 
| 182 | 
            -
                                        return @path[$SPIDER_PATHS[:core_apps].length+1..-1]
         | 
| 183 | 
            -
                                    end
         | 
| 184 | 
            -
                                end
         | 
| 185 | 
            -
                                
         | 
| 186 | 
            -
                                def find_tags
         | 
| 187 | 
            -
                                    return unless File.directory?(@tags_path)
         | 
| 188 | 
            -
                                    Dir.new(@tags_path).each do |entry|
         | 
| 189 | 
            -
                                        next if entry[0].chr == '.'
         | 
| 190 | 
            -
                                        next unless File.extname(entry) == '.erb'
         | 
| 191 | 
            -
                                        name = File.basename(entry, '.erb')
         | 
| 192 | 
            -
                                        klass = Spider::Tag.new_class(File.join(@tags_path, entry))
         | 
| 193 | 
            -
                                        const_set(Spider::Inflector.camelize(name).to_sym, klass)
         | 
| 194 | 
            -
                                        #Spider::Logger.debug("REGISTERED TAG #{name}, #{klass}")
         | 
| 195 | 
            -
                                        register_tag(name, klass)
         | 
| 196 | 
            -
                                    end
         | 
| 197 | 
            -
                                end
         | 
| 209 | 
            +
                        # Finds the path of the resource (see {Spider#find_resource})
         | 
| 210 | 
            +
                        # @return [String]
         | 
| 211 | 
            +
                        def find_resource_path(type, name, cur_path=nil)
         | 
| 212 | 
            +
                            res = Spider.find_resource(type, name, cur_path, self)
         | 
| 213 | 
            +
                            return res ? res.path : nil
         | 
| 214 | 
            +
                        end
         | 
| 215 | 
            +
                        
         | 
| 216 | 
            +
                        # Calls route on the app's controller (see {Dispatcher.route}).
         | 
| 217 | 
            +
                        # @return [nil]
         | 
| 218 | 
            +
                        def route(path, dest=nil, options=nil)
         | 
| 219 | 
            +
                            self.controller.route(path, dest, options)
         | 
| 220 | 
            +
                        end
         | 
| 221 | 
            +
                        
         | 
| 222 | 
            +
                        # @return [String] The app's path, relative to its container (the home or the Spider lib)
         | 
| 223 | 
            +
                        def relative_path
         | 
| 224 | 
            +
                            if Spider.paths[:apps] && @path.index(Spider.paths[:apps]) == 0
         | 
| 225 | 
            +
                                return @path[Spider.paths[:apps].length+1..-1]
         | 
| 226 | 
            +
                            else
         | 
| 227 | 
            +
                                return @path[$SPIDER_PATHS[:core_apps].length+1..-1]
         | 
| 228 | 
            +
                            end
         | 
| 229 | 
            +
                        end
         | 
| 198 230 |  | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
                                
         | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
             | 
| 229 | 
            -
             | 
| 230 | 
            -
             | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 233 | 
            -
                                 | 
| 234 | 
            -
                                    @gettext_parsers ||[]
         | 
| 235 | 
            -
                                end
         | 
| 236 | 
            -
                                
         | 
| 237 | 
            -
                                
         | 
| 238 | 
            -
                                
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                        # Convenience method: since all classes inside the app have an #app method,
         | 
| 233 | 
            +
                        # the App itself has it too
         | 
| 234 | 
            +
                        # @return [self] 
         | 
| 235 | 
            +
                        def app
         | 
| 236 | 
            +
                            self
         | 
| 237 | 
            +
                        end
         | 
| 238 | 
            +
                        
         | 
| 239 | 
            +
                        # Require files inside the App's path
         | 
| 240 | 
            +
                        # @param [file1,file2...] files to require
         | 
| 241 | 
            +
                        # @return [nil]
         | 
| 242 | 
            +
                        def req(*list)
         | 
| 243 | 
            +
                            list.each do |file|
         | 
| 244 | 
            +
                                require File.join(@path, file)
         | 
| 245 | 
            +
                            end
         | 
| 246 | 
            +
                        end
         | 
| 247 | 
            +
                        
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                        
         | 
| 250 | 
            +
                        # Returns the currently installed version of an app
         | 
| 251 | 
            +
                        # @return [Gem::Version]
         | 
| 252 | 
            +
                        def installed_version
         | 
| 253 | 
            +
                            FileUtils.mkpath(File.dirname(installed_version_path))
         | 
| 254 | 
            +
                            return unless File.exist?(installed_version_path)
         | 
| 255 | 
            +
                            return Gem::Version.new(IO.read(installed_version_path))
         | 
| 256 | 
            +
                        end
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                        # Sets the currently installed version of an app
         | 
| 259 | 
            +
                        # @param [String|Gem::Version] version
         | 
| 260 | 
            +
                        # @return [nil]
         | 
| 261 | 
            +
                        def installed_version=(version)
         | 
| 262 | 
            +
                            FileUtils.mkpath(File.dirname(installed_version_path))
         | 
| 263 | 
            +
                            version = Gem::Version.new(version) unless version.is_a?(Gem::Version)
         | 
| 264 | 
            +
                            File.open(installed_version_path, 'w') do |f|
         | 
| 265 | 
            +
                                f << version.to_s
         | 
| 239 266 | 
             
                            end
         | 
| 267 | 
            +
                        end
         | 
| 268 | 
            +
                        
         | 
| 269 | 
            +
                        # Loads the app's .spec file
         | 
| 270 | 
            +
                        # @param [String] spec_path 
         | 
| 271 | 
            +
                        # @return [AppSpec]
         | 
| 272 | 
            +
                        def load_spec(spec_path=nil)
         | 
| 273 | 
            +
                            @spec = AppSpec.load(spec_path)
         | 
| 274 | 
            +
                            @spec.app_id = File.basename(spec_path, 'appsec') unless @spec.app_id
         | 
| 275 | 
            +
                            @version = @spec.version if @spec.version
         | 
| 276 | 
            +
                            @spec
         | 
| 277 | 
            +
                        end
         | 
| 278 | 
            +
                        
         | 
| 279 | 
            +
                        # A list of tettext parsers to use for the app
         | 
| 280 | 
            +
                        # @return [Array]
         | 
| 281 | 
            +
                        def gettext_parsers
         | 
| 282 | 
            +
                            @gettext_parsers || []
         | 
| 283 | 
            +
                        end
         | 
| 240 284 |  | 
| 285 | 
            +
                        # Register the pointer from a widget tag to the an object
         | 
| 286 | 
            +
                        # @param [String] tag
         | 
| 287 | 
            +
                        # @param [String] object
         | 
| 288 | 
            +
                        # @return [void]
         | 
| 289 | 
            +
                        def register_tag(tag, obj)
         | 
| 290 | 
            +
                            @tags ||= {}
         | 
| 291 | 
            +
                            @tags[tag] = obj
         | 
| 241 292 | 
             
                        end
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                        # @param [String] tag
         | 
| 295 | 
            +
                        # @return [Object] The object corresponding to a registered tag
         | 
| 296 | 
            +
                        def get_tag(tag)
         | 
| 297 | 
            +
                            @tags[tag]
         | 
| 298 | 
            +
                        end
         | 
| 299 | 
            +
                        
         | 
| 300 | 
            +
                        # @param [String] tag
         | 
| 301 | 
            +
                        # @return [bool] Whether the given tag is registered
         | 
| 302 | 
            +
                        def has_tag?(tag)
         | 
| 303 | 
            +
                            return false unless @tags
         | 
| 304 | 
            +
                            @tags[tag] ? true : false
         | 
| 305 | 
            +
                        end
         | 
| 306 | 
            +
             | 
| 307 | 
            +
             | 
| 308 | 
            +
                        private
         | 
| 309 | 
            +
             | 
| 310 | 
            +
                        # @private
         | 
| 311 | 
            +
                        # Path to the file with the currently installed version            
         | 
| 312 | 
            +
                        # @return [String]
         | 
| 313 | 
            +
                        def installed_version_path
         | 
| 314 | 
            +
                            File.join(Spider.paths[:var], 'apps', self.name, 'installed_version')
         | 
| 315 | 
            +
                        end
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                        # Looks for erb files in the tags_path
         | 
| 318 | 
            +
                        # @return [nil]
         | 
| 319 | 
            +
                        def find_tags
         | 
| 320 | 
            +
                            return unless File.directory?(@tags_path)
         | 
| 321 | 
            +
                            Dir.new(@tags_path).each do |entry|
         | 
| 322 | 
            +
                                next if entry[0].chr == '.'
         | 
| 323 | 
            +
                                next unless File.extname(entry) == '.erb'
         | 
| 324 | 
            +
                                name = File.basename(entry, '.erb')
         | 
| 325 | 
            +
                                klass = Spider::Tag.new_class(File.join(@tags_path, entry))
         | 
| 326 | 
            +
                                const_set(Spider::Inflector.camelize(name).to_sym, klass)
         | 
| 327 | 
            +
                                #Spider::Logger.debug("REGISTERED TAG #{name}, #{klass}")
         | 
| 328 | 
            +
                                register_tag(name, klass)
         | 
| 329 | 
            +
                            end
         | 
| 330 | 
            +
                        end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                        # Collects models ({BaseModel} subclasses) from inside the module m
         | 
| 333 | 
            +
                        # @param [Module] m
         | 
| 334 | 
            +
                        # @return [Array] the models
         | 
| 335 | 
            +
                        def get_models(m)
         | 
| 336 | 
            +
                            ms = []
         | 
| 337 | 
            +
                            if m.respond_to?(:subclass_of?) && m.subclass_of?(Spider::Model::BaseModel)
         | 
| 338 | 
            +
                                 ms << m
         | 
| 339 | 
            +
                                 m.constants.each do |c|
         | 
| 340 | 
            +
                                     sub_mod = m.const_get(c)
         | 
| 341 | 
            +
                                     next unless sub_mod.is_a?(Module)
         | 
| 342 | 
            +
                                     next if !sub_mod.subclass_of?(Spider::Model::BaseModel) || sub_mod.app != self
         | 
| 343 | 
            +
                                     next if sub_mod == m
         | 
| 344 | 
            +
                                     ms += get_models(sub_mod)
         | 
| 345 | 
            +
                                 end
         | 
| 346 | 
            +
                             elsif (m.is_a?(Module) && !m.is_a?(Class))
         | 
| 347 | 
            +
                                 return models(m)
         | 
| 348 | 
            +
                             end
         | 
| 349 | 
            +
                             return ms
         | 
| 350 | 
            +
                        end
         | 
| 351 | 
            +
                        
         | 
| 352 | 
            +
                    end
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                    def self.included(mod)
         | 
| 355 | 
            +
                        mod.module_eval do
         | 
| 356 | 
            +
                            
         | 
| 357 | 
            +
                            include Spider::DataTypes
         | 
| 358 | 
            +
                            
         | 
| 359 | 
            +
                            extend ClassMethods
         | 
| 360 | 
            +
                        end
         | 
| 361 | 
            +
             | 
| 242 362 | 
             
                        mod.init()
         | 
| 243 363 | 
             
                        Spider::add_app(mod)
         | 
| 244 364 | 
             
                    end
         | 
| 245 365 |  | 
| 366 | 
            +
                    # The AppSpec class represents an app's .spec file
         | 
| 367 | 
            +
                    # The AppSpec attributes are:
         | 
| 368 | 
            +
                    #
         | 
| 369 | 
            +
                    # * :app_id [String]            sunique identifier for the app
         | 
| 370 | 
            +
                    # * :name [String]              descriptive name
         | 
| 371 | 
            +
                    # * :description [String]
         | 
| 372 | 
            +
                    # * :git_repo [String]          URL of git repository for the app
         | 
| 373 | 
            +
                    # * :git_repo_rw [String]       URL of read/write git repository for the app
         | 
| 374 | 
            +
                    # * :authors [Array]
         | 
| 375 | 
            +
                    # * :depends [Array]            Apps this app depends on
         | 
| 376 | 
            +
                    # * :depends_optional [Array]   Optional dependencies
         | 
| 377 | 
            +
                    # * :load_after [Array]         Apps that must be loaded before this one (if present)
         | 
| 378 | 
            +
                    # * :gems [Array]               Gems this app depends on
         | 
| 379 | 
            +
                    # * :gems_optional [Array]      Optional gem dependencies
         | 
| 380 | 
            +
                    # * :version [Gem::Version]     Current app version
         | 
| 381 | 
            +
                    # * :app_server [String]        URL for the app server of this app
         | 
| 382 | 
            +
                    # * :auto_update [TrueClass|FalseClass] true by default; set to false if this version can't be auto-updated
         | 
| 383 | 
            +
             | 
| 246 384 | 
             
                    class AppSpec
         | 
| 385 | 
            +
                        # @private
         | 
| 247 386 | 
             
                        @@attributes = []
         | 
| 248 387 |  | 
| 388 | 
            +
                        # @private
         | 
| 389 | 
            +
                        # Helper method to define an attribute on the AppSpec class
         | 
| 390 | 
            +
                        # @return [nil]
         | 
| 249 391 | 
             
                        def self.attribute(name, options={})
         | 
| 250 392 | 
             
                            @@attributes << name
         | 
| 251 393 | 
             
                            str = <<END_OF_EVAL
         | 
| @@ -260,8 +402,12 @@ END_OF_EVAL | |
| 260 402 | 
             
                                str += "\nalias :#{name}? :#{name}\n"
         | 
| 261 403 | 
             
                            end
         | 
| 262 404 | 
             
                            class_eval(str)
         | 
| 405 | 
            +
                            nil
         | 
| 263 406 | 
             
                        end
         | 
| 264 407 |  | 
| 408 | 
            +
                        # @private
         | 
| 409 | 
            +
                        # Helper method to define an Array attribute on the AppSpec class
         | 
| 410 | 
            +
                        # @return [nil]
         | 
| 265 411 | 
             
                        def self.array_attribute(name, options={})
         | 
| 266 412 | 
             
                            @@attributes << name
         | 
| 267 413 | 
             
                            str = <<END_OF_EVAL
         | 
| @@ -272,6 +418,7 @@ END_OF_EVAL | |
| 272 418 | 
             
                            end
         | 
| 273 419 | 
             
            END_OF_EVAL
         | 
| 274 420 | 
             
                            class_eval(str)
         | 
| 421 | 
            +
                            nil
         | 
| 275 422 | 
             
                        end
         | 
| 276 423 |  | 
| 277 424 | 
             
                        attribute :app_id
         | 
| @@ -283,48 +430,70 @@ END_OF_EVAL | |
| 283 430 | 
             
                        array_attribute :depends
         | 
| 284 431 | 
             
                        array_attribute :depends_optional
         | 
| 285 432 | 
             
                        array_attribute :load_after
         | 
| 286 | 
            -
                        array_attribute :can_use
         | 
| 287 433 | 
             
                        array_attribute :gems
         | 
| 288 434 | 
             
                        array_attribute :gems_optional
         | 
| 289 435 | 
             
                        attribute :version
         | 
| 290 436 | 
             
                        attribute :app_server
         | 
| 291 437 | 
             
                        attribute :auto_update, :default => true
         | 
| 292 438 |  | 
| 439 | 
            +
                        # The git branch used for the app
         | 
| 293 440 | 
             
                        attr_accessor :branch
         | 
| 294 441 |  | 
| 442 | 
            +
                        # Sets or retrieves the AppSpec id
         | 
| 443 | 
            +
                        # @return [String]
         | 
| 295 444 | 
             
                        def id(val=nil)
         | 
| 296 445 | 
             
                            self.app_id(val)
         | 
| 297 446 | 
             
                        end
         | 
| 298 447 |  | 
| 448 | 
            +
                        # Sets or retrieves the AppSpec version
         | 
| 449 | 
            +
                        # @param [String] val
         | 
| 450 | 
            +
                        # @return [Gem::Version]
         | 
| 299 451 | 
             
                        def version(val=nil)
         | 
| 300 452 | 
             
                            @version = Gem::Version.new(val) if val
         | 
| 301 453 | 
             
                            @version
         | 
| 302 454 | 
             
                        end
         | 
| 303 455 |  | 
| 456 | 
            +
                        # Sets or retrieves the first AppSpec author
         | 
| 457 | 
            +
                        # @return [String]
         | 
| 304 458 | 
             
                        def author(val = nil)
         | 
| 305 459 | 
             
                            @authors = [val] if val
         | 
| 306 460 | 
             
                            @authors ||= []
         | 
| 307 461 | 
             
                            @authors[0]
         | 
| 308 462 | 
             
                        end
         | 
| 309 463 |  | 
| 464 | 
            +
                        # Loads attributes from a .spec file
         | 
| 465 | 
            +
                        # @param [String] spec_path
         | 
| 466 | 
            +
                        # @return [self]
         | 
| 310 467 | 
             
                        def load(spec_path)
         | 
| 311 468 | 
             
                            self.eval(File.read(spec_path), spec_path)
         | 
| 312 469 | 
             
                            self
         | 
| 313 470 | 
             
                        end
         | 
| 314 471 |  | 
| 472 | 
            +
                        # Returns a new AppSpec instance, loading from a .spec file
         | 
| 473 | 
            +
                        # @param [String] spec_path
         | 
| 474 | 
            +
                        # @return [AppSpec]
         | 
| 315 475 | 
             
                        def self.load(spec_path)
         | 
| 316 476 | 
             
                            self.new.load(spec_path)
         | 
| 317 477 | 
             
                        end
         | 
| 318 478 |  | 
| 479 | 
            +
             | 
| 480 | 
            +
                        # Evals the given code in the AppSpec's context
         | 
| 481 | 
            +
                        # @return [AppSpec]
         | 
| 319 482 | 
             
                        def eval(text, path=nil)
         | 
| 320 483 | 
             
                            self.instance_eval(text)
         | 
| 321 484 | 
             
                            self
         | 
| 322 485 | 
             
                        end
         | 
| 323 486 |  | 
| 487 | 
            +
                        # Returns a new AppSpec instance, evaluating the given code
         | 
| 488 | 
            +
                        # @param [String] text code to evaluate
         | 
| 489 | 
            +
                        # @param [String] path path to the code
         | 
| 490 | 
            +
                        # @return [AppSpec]
         | 
| 324 491 | 
             
                        def self.eval(text, path=nil)
         | 
| 325 492 | 
             
                            self.new.eval(text, path)
         | 
| 326 493 | 
             
                        end
         | 
| 327 494 |  | 
| 495 | 
            +
                        # Returns all attributes as an Hash
         | 
| 496 | 
            +
                        # @return [Hash]
         | 
| 328 497 | 
             
                        def to_h
         | 
| 329 498 | 
             
                            h = {}
         | 
| 330 499 | 
             
                            @@attributes.each do |a|
         | 
| @@ -334,10 +503,16 @@ END_OF_EVAL | |
| 334 503 | 
             
                            h
         | 
| 335 504 | 
             
                        end
         | 
| 336 505 |  | 
| 506 | 
            +
                        # Returns the Hash (as in #to_hash) as JSON
         | 
| 507 | 
            +
                        # @param [Hash] opts JSON options
         | 
| 508 | 
            +
                        # @return [String]
         | 
| 337 509 | 
             
                        def to_json(opts=nil)
         | 
| 338 510 | 
             
                            to_h.to_json
         | 
| 339 511 | 
             
                        end
         | 
| 340 512 |  | 
| 513 | 
            +
                        # Constructs a new AppSpec instance from an Hash of attributes
         | 
| 514 | 
            +
                        # @param [Hash] h
         | 
| 515 | 
            +
                        # @return [AppSpec]
         | 
| 341 516 | 
             
                        def self.parse_hash(h)
         | 
| 342 517 | 
             
                            spec = self.new
         | 
| 343 518 | 
             
                            h.each do |key, value|
         | 
| @@ -350,21 +525,28 @@ END_OF_EVAL | |
| 350 525 | 
             
                            spec
         | 
| 351 526 | 
             
                        end
         | 
| 352 527 |  | 
| 528 | 
            +
                        # Returns an array of apps needed at runtime
         | 
| 529 | 
            +
                        # @return [Array]
         | 
| 353 530 | 
             
                        def get_runtime_dependencies
         | 
| 354 531 | 
             
                            return self.load_after unless @load_after.blank?
         | 
| 355 532 | 
             
                            return self.depends + self.depends_optional
         | 
| 356 533 | 
             
                        end
         | 
| 357 534 |  | 
| 535 | 
            +
                        # Returns an Array of gem names for gems this AppSpec depends on
         | 
| 536 | 
            +
                        # @return [Array]
         | 
| 358 537 | 
             
                        def gems_list
         | 
| 359 538 | 
             
                            self.gems.map{ |g| g.is_a?(Array) ? g.first : g }
         | 
| 360 539 | 
             
                        end
         | 
| 361 540 |  | 
| 541 | 
            +
                        # Returns an Array of optional gem names
         | 
| 542 | 
            +
                        # @return [Array]
         | 
| 362 543 | 
             
                        def gems_optional_list
         | 
| 363 544 | 
             
                            self.gems_optional.map{ |g| g.is_a?(Array) ? g.first : g }
         | 
| 364 545 | 
             
                        end
         | 
| 365 546 |  | 
| 366 547 | 
             
                    end
         | 
| 367 548 |  | 
| 549 | 
            +
                    # Helper class to sort the runtime dependencies of an app using TSort.
         | 
| 368 550 | 
             
                    class RuntimeSort
         | 
| 369 551 |  | 
| 370 552 | 
             
                        def initialize
         | 
| @@ -372,6 +554,9 @@ END_OF_EVAL | |
| 372 554 | 
             
                            @apps_hash = {}
         | 
| 373 555 | 
             
                        end
         | 
| 374 556 |  | 
| 557 | 
            +
             | 
| 558 | 
            +
                        # Adds an app to be sorted
         | 
| 559 | 
            +
                        # @param [AppSpec|String] app the app to add
         | 
| 375 560 | 
             
                        def add(app)
         | 
| 376 561 | 
             
                            @apps << app
         | 
| 377 562 | 
             
                            if app.is_a?(AppSpec)
         | 
| @@ -381,15 +566,22 @@ END_OF_EVAL | |
| 381 566 | 
             
                            end
         | 
| 382 567 | 
             
                        end
         | 
| 383 568 |  | 
| 569 | 
            +
                        # Runs block on each dependency
         | 
| 570 | 
            +
                        # @param [Proc] block
         | 
| 384 571 | 
             
                        def tsort_each_node(&block)
         | 
| 385 572 | 
             
                            @apps.each(&block)
         | 
| 386 573 | 
             
                        end
         | 
| 387 574 |  | 
| 575 | 
            +
                        # Runs the given block for each dependency of node
         | 
| 576 | 
            +
                        # @param [AppSpec] node the app to get dependecies for
         | 
| 577 | 
            +
                        # @param [Proc] block 
         | 
| 388 578 | 
             
                        def tsort_each_child(node, &block)
         | 
| 389 579 | 
             
                            return unless node.is_a?(AppSpec)
         | 
| 390 580 | 
             
                            node.get_runtime_dependencies.map{ |a| @apps_hash[a] }.each(&block)
         | 
| 391 581 | 
             
                        end
         | 
| 392 582 |  | 
| 583 | 
            +
                        # Runs tsort
         | 
| 584 | 
            +
                        # @return [Array] an array of sorted App ids
         | 
| 393 585 | 
             
                        def tsort
         | 
| 394 586 | 
             
                            sorted = super
         | 
| 395 587 | 
             
                            sorted.map{ |a| a.is_a?(AppSpec) ? a.app_id : a }
         |