ronin 1.0.0 → 1.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. data/.yardopts +0 -1
  2. data/ChangeLog.md +67 -3
  3. data/Gemfile +20 -12
  4. data/README.md +3 -5
  5. data/gemspec.yml +5 -5
  6. data/lib/ronin/address.rb +8 -3
  7. data/lib/ronin/arch.rb +39 -14
  8. data/lib/ronin/author.rb +2 -0
  9. data/lib/ronin/auto_load.rb +67 -0
  10. data/lib/ronin/campaign.rb +15 -2
  11. data/lib/ronin/class_methods.rb +7 -1
  12. data/lib/ronin/config.rb +5 -0
  13. data/lib/ronin/credential.rb +14 -3
  14. data/lib/ronin/database/database.rb +38 -12
  15. data/lib/ronin/database/migrations.rb +3 -1
  16. data/lib/ronin/database/migrations/add_created_at_column_to_targets_table.rb +48 -0
  17. data/lib/ronin/database/migrations/add_updated_at_column_to_campaigns_table.rb +47 -0
  18. data/lib/ronin/database/migrations/create_licenses_table.rb +1 -1
  19. data/lib/ronin/database/migrations/create_passwords_table.rb +1 -1
  20. data/lib/ronin/database/migrations/{create_cached_files_table.rb → create_script_paths_table.rb} +4 -4
  21. data/lib/ronin/database/migrations/migration.rb +3 -6
  22. data/lib/ronin/database/migrations/migrations.rb +3 -3
  23. data/lib/ronin/email_address.rb +20 -3
  24. data/lib/ronin/environment.rb +0 -3
  25. data/lib/ronin/host_name.rb +20 -6
  26. data/lib/ronin/host_name_ip_address.rb +2 -3
  27. data/lib/ronin/installation.rb +92 -23
  28. data/lib/ronin/ip_address.rb +31 -8
  29. data/lib/ronin/ip_address_mac_address.rb +2 -3
  30. data/lib/ronin/license.rb +1 -1
  31. data/lib/ronin/mac_address.rb +6 -4
  32. data/lib/ronin/model/class_methods.rb +4 -0
  33. data/lib/ronin/model/has_authors/class_methods.rb +4 -0
  34. data/lib/ronin/model/has_authors/has_authors.rb +4 -0
  35. data/lib/ronin/model/has_description/class_methods.rb +2 -0
  36. data/lib/ronin/model/has_description/has_description.rb +2 -0
  37. data/lib/ronin/model/has_license/class_methods.rb +2 -0
  38. data/lib/ronin/model/has_license/has_license.rb +4 -0
  39. data/lib/ronin/model/has_name/class_methods.rb +2 -0
  40. data/lib/ronin/model/has_name/has_name.rb +4 -0
  41. data/lib/ronin/model/has_title/class_methods.rb +2 -0
  42. data/lib/ronin/model/has_title/has_title.rb +2 -0
  43. data/lib/ronin/model/has_unique_name/class_methods.rb +2 -0
  44. data/lib/ronin/model/has_unique_name/has_unique_name.rb +7 -1
  45. data/lib/ronin/model/has_version/class_methods.rb +4 -0
  46. data/lib/ronin/model/has_version/has_version.rb +2 -0
  47. data/lib/ronin/model/model.rb +2 -0
  48. data/lib/ronin/model/types.rb +1 -7
  49. data/lib/ronin/model/types/description.rb +2 -0
  50. data/lib/ronin/network/mixins/esmtp.rb +40 -25
  51. data/lib/ronin/network/mixins/http.rb +336 -73
  52. data/lib/ronin/network/mixins/imap.rb +38 -25
  53. data/lib/ronin/network/mixins/pop3.rb +34 -21
  54. data/lib/ronin/network/mixins/smtp.rb +40 -25
  55. data/lib/ronin/network/mixins/tcp.rb +66 -41
  56. data/lib/ronin/network/mixins/telnet.rb +43 -30
  57. data/lib/ronin/network/mixins/udp.rb +59 -40
  58. data/lib/ronin/open_port.rb +12 -5
  59. data/lib/ronin/organization.rb +1 -2
  60. data/lib/ronin/os.rb +10 -3
  61. data/lib/ronin/os_guess.rb +2 -3
  62. data/lib/ronin/password.rb +11 -3
  63. data/lib/ronin/port.rb +7 -2
  64. data/lib/ronin/{engine/exceptions/deploy_failed.rb → repositories.rb} +4 -6
  65. data/lib/ronin/repository.rb +110 -37
  66. data/lib/ronin/ronin.rb +4 -3
  67. data/lib/ronin/{engine.rb → script.rb} +2 -1
  68. data/lib/ronin/{engine → script}/buildable.rb +43 -29
  69. data/lib/ronin/script/class_methods.rb +84 -0
  70. data/lib/ronin/{engine → script}/deployable.rb +61 -40
  71. data/lib/ronin/{engine → script}/exceptions.rb +4 -3
  72. data/lib/ronin/script/exceptions/deploy_failed.rb +27 -0
  73. data/lib/ronin/{engine/exceptions/not_built.rb → script/exceptions/exception.rb} +2 -2
  74. data/lib/ronin/{engine/exceptions/verification_failed.rb → script/exceptions/not_built.rb} +4 -2
  75. data/lib/ronin/script/exceptions/test_failed.rb +27 -0
  76. data/lib/ronin/script/instance_methods.rb +217 -0
  77. data/lib/ronin/script/path.rb +277 -0
  78. data/lib/ronin/{engine/engine.rb → script/script.rb} +52 -15
  79. data/lib/ronin/{engine/verifiable.rb → script/testable.rb} +97 -68
  80. data/lib/ronin/service.rb +1 -2
  81. data/lib/ronin/service_credential.rb +1 -2
  82. data/lib/ronin/software.rb +3 -2
  83. data/lib/ronin/spec/database.rb +0 -4
  84. data/lib/ronin/target.rb +11 -3
  85. data/lib/ronin/tcp_port.rb +3 -2
  86. data/lib/ronin/udp_port.rb +2 -0
  87. data/lib/ronin/ui/cli/cli.rb +6 -0
  88. data/lib/ronin/ui/cli/command.rb +48 -12
  89. data/lib/ronin/ui/cli/commands/campaigns.rb +3 -3
  90. data/lib/ronin/ui/cli/commands/console.rb +2 -1
  91. data/lib/ronin/ui/cli/commands/creds.rb +3 -3
  92. data/lib/ronin/ui/cli/commands/database.rb +1 -17
  93. data/lib/ronin/ui/cli/commands/emails.rb +3 -3
  94. data/lib/ronin/ui/cli/commands/hosts.rb +3 -7
  95. data/lib/ronin/ui/cli/commands/ips.rb +3 -7
  96. data/lib/ronin/ui/cli/commands/repos.rb +5 -17
  97. data/lib/ronin/ui/cli/commands/urls.rb +3 -3
  98. data/lib/ronin/ui/cli/model_command.rb +82 -97
  99. data/lib/ronin/ui/cli/resources_command.rb +89 -0
  100. data/lib/ronin/ui/cli/script_command.rb +115 -0
  101. data/lib/ronin/ui/console.rb +17 -3
  102. data/lib/ronin/ui/output/helpers.rb +18 -0
  103. data/lib/ronin/ui/output/output.rb +20 -1
  104. data/lib/ronin/ui/output/terminal/color.rb +10 -0
  105. data/lib/ronin/ui/output/terminal/raw.rb +10 -0
  106. data/lib/ronin/ui/shell.rb +2 -0
  107. data/lib/ronin/url.rb +47 -12
  108. data/lib/ronin/url_query_param.rb +4 -0
  109. data/lib/ronin/url_scheme.rb +3 -3
  110. data/lib/ronin/user_name.rb +2 -0
  111. data/lib/ronin/version.rb +1 -1
  112. data/lib/ronin/web_credential.rb +6 -3
  113. data/spec/arch_spec.rb +3 -3
  114. data/spec/classes/my_script.rb +21 -0
  115. data/spec/helpers/repos/{test1 → installed}/ronin.yml +1 -1
  116. data/spec/helpers/repos/{hello/cache → installed/scripts}/.keep +0 -0
  117. data/spec/helpers/repos/local/lib/init.rb +1 -0
  118. data/spec/helpers/repos/{hello → local}/lib/stuff/another_test.rb +0 -0
  119. data/spec/helpers/repos/{hello → local}/lib/stuff/test.rb +0 -0
  120. data/spec/helpers/repos/{random → local}/ronin.yml +1 -1
  121. data/spec/helpers/repos/{random/cache → local/scripts}/.keep +0 -0
  122. data/spec/helpers/repos/{hello → remote}/ronin.yml +1 -1
  123. data/spec/helpers/repos/remote/scripts/.keep +0 -0
  124. data/spec/helpers/repos/{test2 → scripts}/ronin.yml +0 -0
  125. data/spec/helpers/repos/scripts/scripts/cached/cached.rb +10 -0
  126. data/spec/helpers/repos/scripts/scripts/cached/missing.rb +10 -0
  127. data/spec/helpers/repos/scripts/scripts/cached/modified.rb +10 -0
  128. data/spec/helpers/repos/scripts/scripts/cached/unmodified.rb +10 -0
  129. data/spec/helpers/repos/scripts/scripts/failures/exceptions.rb +11 -0
  130. data/spec/helpers/repos/{test2/cache/cacheable_model → scripts/scripts/failures}/load_errors.rb +3 -1
  131. data/spec/helpers/repos/{test2/cache/cacheable_model → scripts/scripts/failures}/name_errors.rb +1 -0
  132. data/spec/helpers/repos/scripts/scripts/failures/no_method_errors.rb +10 -0
  133. data/spec/helpers/repos/scripts/scripts/failures/syntax_errors.rb +11 -0
  134. data/spec/helpers/repos/scripts/scripts/failures/validation_errors.rb +11 -0
  135. data/spec/helpers/repos/scripts/scripts/my_scripts/test.rb +16 -0
  136. data/spec/model/spec_helper.rb +0 -2
  137. data/spec/repository_spec.rb +61 -81
  138. data/spec/ronin_spec.rb +2 -2
  139. data/spec/{engine → script}/buildable_spec.rb +9 -9
  140. data/spec/script/classes/buildable_class.rb +15 -0
  141. data/spec/script/classes/deployable_class.rb +13 -0
  142. data/spec/{engine/classes/engine_class.rb → script/classes/script_class.rb} +3 -3
  143. data/spec/{engine/classes/verifiable_class.rb → script/classes/testable_class.rb} +5 -5
  144. data/spec/{engine → script}/deployable_spec.rb +10 -10
  145. data/spec/{cached_file_spec.rb → script/path_spec.rb} +33 -72
  146. data/spec/script/script_spec.rb +130 -0
  147. data/spec/script/testable_spec.rb +117 -0
  148. data/spec/spec_helper.rb +15 -13
  149. metadata +114 -139
  150. data/lib/ronin/cached_file.rb +0 -247
  151. data/lib/ronin/engine/class_methods.rb +0 -135
  152. data/lib/ronin/engine/instance_methods.rb +0 -97
  153. data/lib/ronin/model/cacheable.rb +0 -21
  154. data/lib/ronin/model/cacheable/cacheable.rb +0 -273
  155. data/lib/ronin/model/cacheable/class_methods.rb +0 -60
  156. data/lib/ronin/ui/cli/engine_command.rb +0 -106
  157. data/spec/engine/classes/buildable_class.rb +0 -15
  158. data/spec/engine/classes/deployable_class.rb +0 -13
  159. data/spec/engine/engine_spec.rb +0 -55
  160. data/spec/engine/verifiable_spec.rb +0 -117
  161. data/spec/helpers/repos/hello/lib/init.rb +0 -1
  162. data/spec/helpers/repos/test1/cache/cacheable_model/one.rb +0 -15
  163. data/spec/helpers/repos/test2/cache/cacheable_model/exceptions.rb +0 -7
  164. data/spec/helpers/repos/test2/cache/cacheable_model/no_method_errors.rb +0 -9
  165. data/spec/helpers/repos/test2/cache/cacheable_model/syntax_errors.rb +0 -7
  166. data/spec/helpers/repos/test2/cache/cacheable_model/two.rb +0 -15
  167. data/spec/helpers/repos/test2/cache/cacheable_model/validation_errors.rb +0 -9
  168. data/spec/model/cacheable_spec.rb +0 -96
  169. data/spec/model/models/cacheable_model.rb +0 -13
@@ -17,6 +17,7 @@
17
17
  # along with Ronin. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
19
 
20
- require 'ronin/engine/exceptions/not_built'
21
- require 'ronin/engine/exceptions/verification_failed'
22
- require 'ronin/engine/exceptions/deploy_failed'
20
+ require 'ronin/script/exceptions/exception'
21
+ require 'ronin/script/exceptions/not_built'
22
+ require 'ronin/script/exceptions/test_failed'
23
+ require 'ronin/script/exceptions/deploy_failed'
@@ -0,0 +1,27 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin.
5
+ #
6
+ # Ronin is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Ronin. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/script/exceptions/exception'
21
+
22
+ module Ronin
23
+ module Script
24
+ class DeployFailed < Exception
25
+ end
26
+ end
27
+ end
@@ -18,8 +18,8 @@
18
18
  #
19
19
 
20
20
  module Ronin
21
- module Engine
22
- class NotBuilt < RuntimeError
21
+ module Script
22
+ class Exception < RuntimeError
23
23
  end
24
24
  end
25
25
  end
@@ -17,9 +17,11 @@
17
17
  # along with Ronin. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
19
 
20
+ require 'ronin/script/exceptions/exception'
21
+
20
22
  module Ronin
21
- module Engine
22
- class VerificationFailed < RuntimeError
23
+ module Script
24
+ class NotBuilt < Exception
23
25
  end
24
26
  end
25
27
  end
@@ -0,0 +1,27 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin.
5
+ #
6
+ # Ronin is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Ronin. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/script/exceptions/exception'
21
+
22
+ module Ronin
23
+ module Script
24
+ class TestFailed < Exception
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,217 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin.
5
+ #
6
+ # Ronin is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Ronin. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ module Ronin
21
+ module Script
22
+ #
23
+ # Instance methods for an {Script}.
24
+ #
25
+ # @since 1.1.0
26
+ #
27
+ module InstanceMethods
28
+ #
29
+ # Initializes the Ronin Script.
30
+ #
31
+ # @param [Array] arguments
32
+ # Arguments for initializing the Script.
33
+ #
34
+ # @since 1.1.0
35
+ #
36
+ # @api semipublic
37
+ #
38
+ def initialize(*arguments,&block)
39
+ @script_loaded = false
40
+ @cache_prepared = false
41
+
42
+ if arguments.first.kind_of?(Hash)
43
+ initialize_params(arguments.first)
44
+ end
45
+
46
+ super(*arguments,&block)
47
+ end
48
+
49
+ #
50
+ # The script type.
51
+ #
52
+ # @return [String]
53
+ # The name of the script class.
54
+ #
55
+ # @since 1.1.0
56
+ #
57
+ # @api semipublic
58
+ #
59
+ def script_type
60
+ @script_type ||= self.class.base_model.name.split('::').last
61
+ end
62
+
63
+ #
64
+ # Determines if the original code, from the cache file, has been
65
+ # loaded into the object.
66
+ #
67
+ # @return [Boolean]
68
+ # Specifies whether the original code has been loaded into the
69
+ # object.
70
+ #
71
+ # @since 1.1.0
72
+ #
73
+ # @api private
74
+ #
75
+ def script_loaded?
76
+ @script_loaded == true
77
+ end
78
+
79
+ #
80
+ # Loads the code from the cached file for the object, and instance
81
+ # evaluates it into the object.
82
+ #
83
+ # @return [Boolean]
84
+ # Indicates the original code was successfully loaded.
85
+ #
86
+ # @since 1.1.0
87
+ #
88
+ # @api private
89
+ #
90
+ def load_script!
91
+ if (cached? && !script_loaded?)
92
+ block = self.class.load_object_block(self.script_path.path)
93
+
94
+ @script_loaded = true
95
+ instance_eval(&block) if block
96
+ return true
97
+ end
98
+
99
+ return false
100
+ end
101
+
102
+ #
103
+ # @return [Boolean]
104
+ # Specifies whether the object has been prepared to be cached,
105
+ #
106
+ # @since 1.1.0
107
+ #
108
+ # @api private
109
+ #
110
+ def prepared_for_cache?
111
+ @cache_prepared == true
112
+ end
113
+
114
+ #
115
+ # Indicates whether the object has been cached.
116
+ #
117
+ # @return [Boolean]
118
+ # Specifies whether the object has been previously cached.
119
+ #
120
+ # @since 1.1.0
121
+ #
122
+ # @api private
123
+ #
124
+ def cached?
125
+ (saved? && self.script_path)
126
+ end
127
+
128
+ #
129
+ # Default method which invokes the script.
130
+ #
131
+ # @param [Array] arguments
132
+ # Optional arguments.
133
+ #
134
+ # @since 1.1.0
135
+ #
136
+ def run(*arguments)
137
+ end
138
+
139
+ #
140
+ # Converts the script to a String.
141
+ #
142
+ # @return [String]
143
+ # The name and version of the script.
144
+ #
145
+ # @since 1.1.0
146
+ #
147
+ # @api public
148
+ #
149
+ def to_s
150
+ if (self.name && self.version)
151
+ "#{self.name} #{self.version}"
152
+ elsif self.name
153
+ super
154
+ elsif self.version
155
+ self.version.to_s
156
+ end
157
+ end
158
+
159
+ #
160
+ # Inspects both the properties and parameters of the Ronin Script.
161
+ #
162
+ # @return [String]
163
+ # The inspected Ronin Script.
164
+ #
165
+ # @since 1.1.0
166
+ #
167
+ # @api public
168
+ #
169
+ def inspect
170
+ body = []
171
+
172
+ self.attributes.each do |name,value|
173
+ body << "#{name}: #{value.inspect}"
174
+ end
175
+
176
+ param_pairs = []
177
+
178
+ self.params.each do |name,param|
179
+ param_pairs << "#{name}: #{param.value.inspect}"
180
+ end
181
+
182
+ body << "params: {#{param_pairs.join(', ')}}"
183
+
184
+ return "#<#{self.class}: #{body.join(', ')}>"
185
+ end
186
+
187
+ protected
188
+
189
+ #
190
+ # Will call the given block only once, in order to prepare the
191
+ # object for caching.
192
+ #
193
+ # @yield []
194
+ # The block will be ran inside the object when the object is to be
195
+ # prepared for caching.
196
+ #
197
+ # @return [Boolean]
198
+ # Specifies whether the object was successfully prepared for
199
+ # caching.
200
+ #
201
+ # @since 1.1.0
202
+ #
203
+ # @api public
204
+ #
205
+ def cache
206
+ if (block_given? && !(cached? || prepared_for_cache?))
207
+ @cache_prepared = true
208
+
209
+ yield
210
+ return true
211
+ end
212
+
213
+ return false
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,277 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin.
5
+ #
6
+ # Ronin is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Ronin. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/model'
21
+ require 'ronin/repository'
22
+ require 'ronin/script/script'
23
+ require 'ronin/support/inflector'
24
+
25
+ require 'object_loader'
26
+
27
+ module Ronin
28
+ module Script
29
+ #
30
+ # The {Path} model stores information in the {Database} about
31
+ # cached {Script} objects.
32
+ #
33
+ # @since 1.1.0
34
+ #
35
+ class Path
36
+
37
+ include Model
38
+
39
+ # The primary key of the cached file
40
+ property :id, Serial
41
+
42
+ # The path to the file where the object was defined in
43
+ property :path, FilePath, :required => true
44
+
45
+ # The timestamp of the cached file
46
+ property :timestamp, Time, :required => true
47
+
48
+ # The class name of the cached object
49
+ property :class_name, String, :required => true
50
+
51
+ # The repository the file was cached from
52
+ belongs_to :repository
53
+
54
+ # Any exceptions raise when loading a fresh object
55
+ attr_reader :cache_exception
56
+
57
+ # Any cache errors encountered when caching the object
58
+ attr_reader :cache_errors
59
+
60
+ #
61
+ # The path to require to access the Class of the cached object.
62
+ #
63
+ # @return [String]
64
+ # The possible path inferred from the class name.
65
+ #
66
+ # @since 1.1.0
67
+ #
68
+ def class_path
69
+ if self.class_name
70
+ Support::Inflector.underscore(self.class_name)
71
+ end
72
+ end
73
+
74
+ #
75
+ # The Model of the cached object.
76
+ #
77
+ # @return [Class, nil]
78
+ # Returns the Model of the cached object, or `nil` if the class
79
+ # could not be loaded or found.
80
+ #
81
+ # @since 1.1.0
82
+ #
83
+ def script_class
84
+ return unless self.class_name
85
+
86
+ # filter out unloadable script classes
87
+ begin
88
+ require class_path
89
+ rescue Gem::LoadError => e
90
+ raise(e)
91
+ rescue ::LoadError
92
+ end
93
+
94
+ # filter out missing class names
95
+ loaded_class = begin
96
+ DataMapper::Ext::Object.full_const_get(self.class_name)
97
+ rescue NameError
98
+ return nil
99
+ end
100
+
101
+ # filter out non-script classes
102
+ return loaded_class if loaded_class < Script
103
+ end
104
+
105
+ #
106
+ # The object from the Database that was cached from the file.
107
+ #
108
+ # @return [Model]
109
+ # The previously cached object connected to the cache file.
110
+ #
111
+ # @since 1.1.0
112
+ #
113
+ def cached_script
114
+ if (cached_class = script_class)
115
+ return cached_class.first(:script_path => self)
116
+ end
117
+ end
118
+
119
+ #
120
+ # A freshly loaded {Script} object from the cache file.
121
+ #
122
+ # @return [Script, nil]
123
+ # The first {Script} object loaded from the cache file.
124
+ # If `nil` is returned, the file did not contain any cacheable
125
+ # objects or the cache file contained a syntax error.
126
+ #
127
+ # @since 1.1.0
128
+ #
129
+ def load_script
130
+ begin
131
+ # load the first found object
132
+ blocks = ObjectLoader.load_blocks(self.path)
133
+ rescue ::Exception => e
134
+ @cache_exception = e
135
+ return nil
136
+ end
137
+
138
+ blocks.each do |object_class,object_block|
139
+ if object_class < Script
140
+ # create the fresh object
141
+ object = object_class.new()
142
+
143
+ begin
144
+ object.instance_eval(&object_block)
145
+
146
+ @cache_exception = nil
147
+ return object
148
+ rescue ::Exception => e
149
+ @cache_exception = e
150
+ end
151
+ end
152
+ end
153
+
154
+ return nil
155
+ end
156
+
157
+ #
158
+ # Determines if the cache file was updated.
159
+ #
160
+ # @return [Boolean]
161
+ # Specifies whether the cache file was updated.
162
+ #
163
+ # @since 1.1.0
164
+ #
165
+ def updated?
166
+ # assume updates if there is no timestamp
167
+ return true unless self.timestamp
168
+
169
+ if File.file?(self.path)
170
+ return self.path.mtime > self.timestamp
171
+ end
172
+
173
+ # do not assume updates, if there is no path
174
+ return false
175
+ end
176
+
177
+ #
178
+ # Determines if the cache file was deleted.
179
+ #
180
+ # @return [Boolean]
181
+ # Specifies whether the cache file was deleted.
182
+ #
183
+ # @since 1.1.0
184
+ #
185
+ def missing?
186
+ !(self.path.file?)
187
+ end
188
+
189
+ #
190
+ # Caches the freshly loaded object from the cache file into the
191
+ # Database.
192
+ #
193
+ # @return [Boolean]
194
+ # Specifies whether the object was successfully cached.
195
+ #
196
+ # @since 1.1.0
197
+ #
198
+ def cache
199
+ if (new_script = load_script)
200
+ # reset the model-class
201
+ self.class_name = new_script.class.to_s
202
+
203
+ # update the timestamp
204
+ self.timestamp = self.path.mtime
205
+
206
+ # re-cache the newly loaded script
207
+ new_script.script_path = self
208
+
209
+ if new_script.save
210
+ @cache_errors = nil
211
+ return true
212
+ else
213
+ @cache_errors = new_script.errors
214
+ end
215
+ end
216
+
217
+ return false
218
+ end
219
+
220
+ #
221
+ # Syncs the cached object in the Database with the object loaded from
222
+ # the cache file.
223
+ #
224
+ # @return [Boolean]
225
+ # Specifies whether the cached object was successfully synced.
226
+ #
227
+ # @since 1.1.0
228
+ #
229
+ def sync
230
+ if missing?
231
+ # destroy the cached file, if the actual file is missing
232
+ return destroy
233
+ elsif updated?
234
+ if (script = cached_script)
235
+ # destroy the previously cached object
236
+ script.destroy!
237
+ end
238
+
239
+ # if we couldn't cache anything, self-destruct
240
+ destroy unless cache
241
+ return true
242
+ end
243
+
244
+ return false
245
+ end
246
+
247
+ #
248
+ # Before destroying the cached file object, also destroy the
249
+ # associated cached object.
250
+ #
251
+ # @since 1.1.0
252
+ #
253
+ def destroy
254
+ unless destroyed?
255
+ if (script = cached_script)
256
+ script.destroy!
257
+ end
258
+ end
259
+
260
+ super
261
+ end
262
+
263
+ #
264
+ # Converts the script path to a String.
265
+ #
266
+ # @return [String]
267
+ # The path of the script path.
268
+ #
269
+ # @since 1.1.0
270
+ #
271
+ def to_s
272
+ self.path.to_s
273
+ end
274
+
275
+ end
276
+ end
277
+ end