app_drone 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -189,7 +189,43 @@ For convenience, `method_missing` is used to allow you to use the underscore'd n
189
189
  end
190
190
  end
191
191
 
192
- **Take a look at existing drones for more info!**
192
+
193
+ ## DependencyChain
194
+
195
+ The `DependencyChain` class is used to test if a collection of drones is self-sufficient.
196
+
197
+ DependencyChain.satisfied? [AppDrone::Bundle, AppDrone::Stylesheet]
198
+ # => true
199
+
200
+ DependencyChain.satisfied? [AppDrone::Bundle, AppDrone::Flair]
201
+ # => false
202
+
203
+ DependencyChain.satisfaction_requirements [AppDrone::Bundle, AppDrone::Flair]
204
+ # => [AppDrone::HighVoltage, AppDrone::SlimView]
205
+
206
+ Note that only immediate requirements are output. Consider, if `A` depends on `B`, and `B` depends on `C`:
207
+
208
+ DependencyChain.satisfaction_requirements ['A']
209
+ # => ['B']
210
+
211
+ DependencyChain.satisfied? ['A','B']
212
+ # => false
213
+
214
+ DependencyChain.satisfaction_requirements ['A','B']
215
+ # => ['C']
216
+
217
+ DependencyChain.satisfied? ['A','B','C']
218
+ # => true
219
+
220
+ You can also sort a collection of drones so that each drone appears after its respective dependencies:
221
+
222
+ DependencyChain.sort [AppDrone::Flair, AppDrone::HighVoltage, AppDrone::Bundle, AppDrone::SlimView]
223
+ # => [AppDrone::Bundle, AppDrone::HighVoltage, AppDrone::SlimView, AppDrone::Flair]
224
+
225
+
226
+ ### More info
227
+
228
+ **Take a look at existing drones to gain a deeper understanding of how they work**
193
229
 
194
230
 
195
231
  ### Drone naming caveat
data/README.md~ CHANGED
@@ -189,7 +189,43 @@ For convenience, `method_missing` is used to allow you to use the underscore'd n
189
189
  end
190
190
  end
191
191
 
192
- **Take a look at existing drones for more info!**
192
+
193
+ ## DependencyChain
194
+
195
+ The `DependencyChain` class is used to test if a collection of drones is self-sufficient.
196
+
197
+ DependencyChain.satisfied? [AppDrone::Bundle, AppDrone::Stylesheet]
198
+ # => true
199
+
200
+ DependencyChain.satisfied? [AppDrone::Bundle, AppDrone::Flair]
201
+ # => false
202
+
203
+ DependencyChain.satisfaction_requirements [AppDrone::Bundle, AppDrone::Flair]
204
+ # => [AppDrone::HighVoltage, AppDrone::SlimView]
205
+
206
+ Note that only immediate requirements are output. Consider, if `A` depends on `B`, and `B` depends on `C`:
207
+
208
+ DependencyChain.satisfaction_requirements ['A']
209
+ # => ['B']
210
+
211
+ DependencyChain.satisfied? ['A','B']
212
+ # => false
213
+
214
+ DependencyChain.satisfaction_requirements ['A','B']
215
+ # => ['C']
216
+
217
+ DependencyChain.satisfied? ['A','B','C']
218
+ # => true
219
+
220
+ You can also sort a collection of drones so that each drone appears after its respective dependencies:
221
+
222
+ DependencyChain.sort [AppDrone::Flair, AppDrone::HighVoltage, AppDrone::Bundle, AppDrone::SlimView]
223
+ # => [AppDrone::Bundle, AppDrone::HighVoltage, AppDrone::SlimView, AppDrone::Flair]
224
+
225
+
226
+ ### More info
227
+
228
+ **Take a look at existing drones to gain a deeper understanding of how they work**
193
229
 
194
230
 
195
231
  ### Drone naming caveat
@@ -236,6 +272,7 @@ AppDrone is not for everyone. It's highly opinionated about how a Rails app shou
236
272
  - SlimViews: Add browser-specific classes to <html> via useragent + helpers..
237
273
  - UserAgent blocking script
238
274
  - Responders
275
+ - Bootstrap: vendor files rather than gem require
239
276
  - EasyRoles
240
277
  - Migrant
241
278
  - HasScope
data/TODO CHANGED
@@ -1,4 +1 @@
1
- ** templates must be added and run in the order that satisfies dependency order best. (also consider pairings if possible)
2
- i.e. a drone can only run after it's dependants have had their turn (unless they mutually depend)
3
-
4
1
  ** rename pairs/pairs_with to connections/connects_with
data/TODO~ CHANGED
@@ -1,6 +1,4 @@
1
1
  ** templates must be added and run in the order that satisfies dependency order best. (also consider pairings if possible)
2
2
  i.e. a drone can only run after it's dependants have had their turn (unless they mutually depend)
3
3
 
4
- ** param 'default' values... (when accessing param, if nil, return default (unless default is nil too))
5
-
6
4
  ** rename pairs/pairs_with to connections/connects_with
@@ -0,0 +1,5 @@
1
+ module AppDrone
2
+ class Dependency
3
+ def initialize()
4
+ end
5
+ end
@@ -0,0 +1,55 @@
1
+ module AppDrone
2
+ class DependencyChain
3
+ # re-orders a list of drones so that every drone appears
4
+ # after all of its dependencies
5
+
6
+ class << self
7
+ def satisfied?(drones)
8
+ satisfaction_requirements(drones).empty?
9
+ end
10
+
11
+ def satisfaction_requirements(drones)
12
+ all_dependencies = drones.map(&:dependencies).flatten.uniq
13
+ return all_dependencies - drones
14
+ end
15
+
16
+ def check_dependencies!(drones)
17
+ raise "Unsatisfied dependencies: #{satisfaction_requirements(drones)}" unless satisfied?(drones)
18
+ end
19
+
20
+ def sort(drones)
21
+ raise ArgumentError unless drones.is_a?(Array)
22
+ check_dependencies!(drones)
23
+
24
+ misplaced_drone = drones.reverse.find do |drone|
25
+ # working from the bottom of the list upwards,
26
+ # try to find a drone who is below one of their dependencies
27
+ dependency_indices(drones,drone).any? { |dependency_index| drones.index(drone) < dependency_index }
28
+ end
29
+
30
+ if misplaced_drone
31
+ # move it to where it belongs
32
+ drones_sans_misplaced = drones - [misplaced_drone]
33
+ drone_new_index = last_dependency_index(drones_sans_misplaced,misplaced_drone) + 1
34
+ shuffled_drones = drones_sans_misplaced.insert(drone_new_index,misplaced_drone)
35
+
36
+ # resolve recursively
37
+ return sort(shuffled_drones)
38
+ else
39
+ return drones
40
+ end
41
+ end
42
+
43
+ private
44
+ def dependency_indices(drones,drone)
45
+ drone.dependencies.map { |d| drones.index(d) }
46
+ end
47
+
48
+ def last_dependency_index(drones,drone)
49
+ dependency_indices(drones,drone).sort.last
50
+ end
51
+ end
52
+
53
+
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ module AppDrone
2
+ class DependencyChain
3
+ # re-orders a list of drones so that every drone appears
4
+ # after all of its dependencies
5
+
6
+ class << self
7
+ def satisfied?(drones)
8
+ satisfaction_requirements(drones).empty?
9
+ end
10
+
11
+ def satisfaction_requirements(drones)
12
+ all_dependencies = drones.map(&:dependencies).flatten.uniq
13
+ return all_dependencies - drones
14
+ end
15
+
16
+ def check_dependencies!(drones)
17
+ raise "Unsatisfied dependencies: #{satisfaction_requirements(drones)}" unless satisfied?(drones)
18
+ end
19
+
20
+ def sort(drones)
21
+ raise ArgumentError unless drones.is_a?(Array)
22
+ check_dependencies!(drones)
23
+
24
+ misplaced_drone = drones.reverse.find do |drone|
25
+ # working from the bottom of the list upwards,
26
+ # try to find a drone who is below one of their dependencies
27
+ dependency_indices(drones,drone).any? { |dependency_index| drones.index(drone) < dependency_index }
28
+ end
29
+
30
+ if misplaced_drone
31
+ # move it to where it belongs
32
+ drones_sans_misplaced = drones - [misplaced_drone]
33
+ drone_new_index = last_dependency_index(drones_sans_misplaced,misplaced_drone) + 1
34
+ shuffled_drones = drones_sans_misplaced.insert(drone_new_index,misplaced_drone)
35
+
36
+ # resolve recursively
37
+ return sort(shuffled_drones)
38
+ else
39
+ return drones
40
+ end
41
+ end
42
+
43
+ private
44
+ def dependency_indices(drones,drone)
45
+ drone.dependencies.map { |d| drones.index(d) }
46
+ end
47
+
48
+ def last_dependency_index(drones,drone)
49
+ dependency_indices(drones,drone).sort.last
50
+ end
51
+ end
52
+
53
+
54
+ end
55
+ end
@@ -10,6 +10,7 @@ class Bootstrap < Drone
10
10
  param :javascript_plugins, :choose_many, info: 'pipeline javascript plugin files', default: [], choices: %w(modal dropdown scrollspy tab tooltip popover alert button collapse carousel typeahead)
11
11
 
12
12
  depends_on :bundle, :stylesheet, :javascript
13
+ pairs_with :flair
13
14
 
14
15
  def align
15
16
  bundle.add 'compass_twitter_bootstrap', git: 'git://github.com/vwall/compass-twitter-bootstrap.git', group: :assets
@@ -10,6 +10,7 @@ class Bootstrap < Drone
10
10
  param :javascript_plugins, :choose_many, info: 'pipeline javascript plugin files', default: [], choices: %w(modal dropdown scrollspy tab tooltip popover alert button collapse carousel typeahead)
11
11
 
12
12
  depends_on :bundle, :stylesheet, :javascript
13
+ pairs_with :flair
13
14
 
14
15
  def align
15
16
  bundle.add 'compass_twitter_bootstrap', git: 'git://github.com/vwall/compass-twitter-bootstrap.git', group: :assets
@@ -2,6 +2,6 @@
2
2
  a.btn.btn-primary.btn-large Shiny!
3
3
  <% if param(:font_awesome) %>
4
4
  a.btn.btn-large
5
- i.icon-heart
5
+ i.icon-thumbs-up
6
6
  | with Font Awesome!
7
7
  <% end %>
@@ -4,6 +4,8 @@ class Javascript < Drone
4
4
  category :base
5
5
  attr_accessor :pipeline_requires, :on_readies
6
6
 
7
+ depends_on :bundle # not really, but makes for good ordering in DependencyChain
8
+
7
9
  def setup
8
10
  self.pipeline_requires = []
9
11
  self.on_readies = []
@@ -4,6 +4,8 @@ class Javascript < Drone
4
4
  category :base
5
5
  attr_accessor :pipeline_requires, :on_readies
6
6
 
7
+ depends_on :bundle # not really, but makes for good ordering in DependencyChain
8
+
7
9
  def setup
8
10
  self.pipeline_requires = []
9
11
  self.on_readies = []
@@ -9,7 +9,6 @@ class SimpleForm < Drone
9
9
 
10
10
  param :add_country_select, :boolean, info: 'Add country_select for listing countries', default: true
11
11
 
12
-
13
12
  def align
14
13
  bundle.add 'simple_form'
15
14
  bundle.add 'country_select' if param(:add_country_select)
@@ -1,4 +1,5 @@
1
- class AppDrone::Template
1
+ module AppDrone
2
+ class Template
2
3
  def initialize; @drones = {}; @directives = {} end
3
4
 
4
5
  def add(ref,*params)
@@ -22,18 +23,9 @@ class AppDrone::Template
22
23
  (@directives[generator_method] ||= []) << d
23
24
  end
24
25
 
25
- def check_dependencies
26
- drone_classes.each { |drone_class|
27
- drone_class.dependencies.each { |d|
28
- dependency = d.to_s.classify
29
- raise "#{drone_class} depends on #{dependency}, but it is not included in the template." unless drone_classes.include?(d)
30
- }
31
- }
32
- end
33
-
34
26
  def render!
35
27
  return if @rendered
36
- check_dependencies
28
+ DependencyChain.check_dependencies!(drone_classes)
37
29
  drone_objects.map(&:align)
38
30
  drone_objects.map(&:execute)
39
31
  @rendered = true
@@ -58,5 +50,5 @@ class AppDrone::Template
58
50
  f.write(render_with_wrapper)
59
51
  end
60
52
  end
61
-
53
+ end
62
54
  end
@@ -1,4 +1,5 @@
1
- class AppDrone::Template
1
+ module AppDrone
2
+ class Template
2
3
  def initialize; @drones = {}; @directives = {} end
3
4
 
4
5
  def add(ref,*params)
@@ -22,18 +23,9 @@ class AppDrone::Template
22
23
  (@directives[generator_method] ||= []) << d
23
24
  end
24
25
 
25
- def check_dependencies
26
- drone_classes.each { |drone_class|
27
- drone_class.dependencies.each { |d|
28
- dependency = d.to_s.classify
29
- raise "#{drone_class} depends on #{dependency}, but it is not included in the template." unless drone_classes.include?(d)
30
- }
31
- }
32
- end
33
-
34
26
  def render!
35
27
  return if @rendered
36
- check_dependencies
28
+ DependencyChain.check_dependencies!(drone_classes)
37
29
  drone_objects.map(&:align)
38
30
  drone_objects.map(&:execute)
39
31
  @rendered = true
@@ -58,5 +50,5 @@ class AppDrone::Template
58
50
  f.write(render_with_wrapper)
59
51
  end
60
52
  end
61
-
53
+ end
62
54
  end
@@ -1,3 +1,3 @@
1
1
  module AppDrone
2
- VERSION = "0.5.2"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -1,3 +1,3 @@
1
1
  module AppDrone
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
data/lib/app_drone.rb CHANGED
@@ -3,7 +3,7 @@ require 'erb'
3
3
  require 'active_support/inflector'
4
4
 
5
5
  # require lib files
6
- lib_files = %w(version template drone object_extensions)
6
+ lib_files = %w(version dependency_chain template drone object_extensions)
7
7
  lib_files.each { |f| require "app_drone/#{f}" }
8
8
 
9
9
  # require all drones in app_drone/drones, exclude 'zzz' folder
@@ -13,5 +13,4 @@ drones -= ['zzz']
13
13
  drones.each { |d| require "app_drone/drones/#{d}/#{d}" }
14
14
 
15
15
  module AppDrone
16
- # TODO Your code goes here...
17
16
  end
data/lib/app_drone.rb~ CHANGED
@@ -3,15 +3,14 @@ require 'erb'
3
3
  require 'active_support/inflector'
4
4
 
5
5
  # require lib files
6
- lib_files = %w(version template drone object_extensions)
6
+ lib_files = %w(version dependency_chain template drone object_extensions)
7
7
  lib_files.each { |f| require "app_drone/#{f}" }
8
8
 
9
- # require all drones in app_drone/drones
9
+ # require all drones in app_drone/drones, exclude 'zzz' folder
10
10
  drone_paths = Pathname.new(File.dirname(__FILE__) + '/app_drone/drones')
11
11
  drones = drone_paths.children.select(&:directory?).map { |path| path.split.last.to_s }
12
12
  drones -= ['zzz']
13
13
  drones.each { |d| require "app_drone/drones/#{d}/#{d}" }
14
14
 
15
15
  module AppDrone
16
- # TODO Your code goes here...
17
16
  end
data/out.rb CHANGED
@@ -122,7 +122,7 @@ h3 Bootstrap
122
122
  a.btn.btn-primary.btn-large Shiny!
123
123
 
124
124
  a.btn.btn-large
125
- i.icon-heart
125
+ i.icon-thumbs-up
126
126
  | with Font Awesome!
127
127
 
128
128
 
@@ -3,7 +3,7 @@ require 'app_drone'
3
3
 
4
4
  module AppDrone
5
5
 
6
- # Yes, I know this isn't real testing, but I can't get the CLI to work
6
+ # I know this isn't full testing, but I can't get the CLI to work
7
7
  # (due to the requires), so this is my only way of testing the damn
8
8
  # thing semi-manually
9
9
 
@@ -37,6 +37,31 @@ class AppDroneTest < Test::Unit::TestCase
37
37
  assert_equal drone_symbol.to_app_drone_class, AppDrone::Bundle
38
38
  end
39
39
 
40
+ def test_dependency_chain_satisfaction
41
+ # single dependency
42
+ assert_equal DependencyChain.satisfied?([AppDrone::Stylesheet]), false
43
+ assert_equal DependencyChain.satisfied?([AppDrone::Stylesheet,AppDrone::Bundle]), true
44
+
45
+ # complex dependency
46
+ chain = [AppDrone::Bootstrap, AppDrone::Javascript, AppDrone::Stylesheet, AppDrone::Flair]
47
+ assert_equal DependencyChain.satisfied?(chain), false
48
+
49
+ chain << AppDrone::Bundle
50
+ assert_equal DependencyChain.satisfied?(chain), false
51
+
52
+ chain << AppDrone::SlimView
53
+ assert_equal DependencyChain.satisfied?(chain), false
54
+
55
+ chain << AppDrone::HighVoltage
56
+ assert_equal DependencyChain.satisfied?(chain), true
57
+ end
58
+
59
+ def test_dependency_chain_sorting
60
+ chain = [AppDrone::Bootstrap, AppDrone::Flair, AppDrone::SlimView, AppDrone::Javascript, AppDrone::Stylesheet, AppDrone::Bundle, AppDrone::HighVoltage]
61
+ sorted_chain = [AppDrone::Bundle, AppDrone::SlimView, AppDrone::Javascript, AppDrone::Stylesheet, AppDrone::Bootstrap, AppDrone::HighVoltage, AppDrone::Flair]
62
+ assert_equal DependencyChain.sort(chain), sorted_chain
63
+ end
64
+
40
65
  private
41
66
  def add_defaults_to_template(template)
42
67
  defaults = [:bundle, :javascript, :stylesheet, :slim_view, :high_voltage, :flair, :cleanup]
@@ -3,7 +3,7 @@ require 'app_drone'
3
3
 
4
4
  module AppDrone
5
5
 
6
- # Yes, I know this isn't real testing, but I can't get the CLI to work
6
+ # I know this isn't full testing, but I can't get the CLI to work
7
7
  # (due to the requires), so this is my only way of testing the damn
8
8
  # thing semi-manually
9
9
 
@@ -15,6 +15,10 @@ class AppDroneTest < Test::Unit::TestCase
15
15
  def setup
16
16
  end
17
17
 
18
+ def test_blah
19
+ puts DependencyChain.sort [AppDrone::Flair, AppDrone::HighVoltage, AppDrone::Bundle, AppDrone::SlimView]
20
+ end
21
+
18
22
  def test_basic_behavior
19
23
  template = Template.new
20
24
  add_defaults_to_template(template)
@@ -37,6 +41,31 @@ class AppDroneTest < Test::Unit::TestCase
37
41
  assert_equal drone_symbol.to_app_drone_class, AppDrone::Bundle
38
42
  end
39
43
 
44
+ def test_dependency_chain_satisfaction
45
+ # single dependency
46
+ assert_equal DependencyChain.satisfied?([AppDrone::Stylesheet]), false
47
+ assert_equal DependencyChain.satisfied?([AppDrone::Stylesheet,AppDrone::Bundle]), true
48
+
49
+ # complex dependency
50
+ chain = [AppDrone::Bootstrap, AppDrone::Javascript, AppDrone::Stylesheet, AppDrone::Flair]
51
+ assert_equal DependencyChain.satisfied?(chain), false
52
+
53
+ chain << AppDrone::Bundle
54
+ assert_equal DependencyChain.satisfied?(chain), false
55
+
56
+ chain << AppDrone::SlimView
57
+ assert_equal DependencyChain.satisfied?(chain), false
58
+
59
+ chain << AppDrone::HighVoltage
60
+ assert_equal DependencyChain.satisfied?(chain), true
61
+ end
62
+
63
+ def test_dependency_chain_sorting
64
+ chain = [AppDrone::Bootstrap, AppDrone::Flair, AppDrone::SlimView, AppDrone::Javascript, AppDrone::Stylesheet, AppDrone::Bundle, AppDrone::HighVoltage]
65
+ sorted_chain = [AppDrone::Bundle, AppDrone::SlimView, AppDrone::Javascript, AppDrone::Stylesheet, AppDrone::Bootstrap, AppDrone::HighVoltage, AppDrone::Flair]
66
+ assert_equal DependencyChain.sort(chain), sorted_chain
67
+ end
68
+
40
69
  private
41
70
  def add_defaults_to_template(template)
42
71
  defaults = [:bundle, :javascript, :stylesheet, :slim_view, :high_voltage, :flair, :cleanup]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app_drone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-04-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &16850440 !ruby/object:Gem::Requirement
16
+ requirement: &15442500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 3.2.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *16850440
24
+ version_requirements: *15442500
25
25
  description: Give your Rails apps a kickstart
26
26
  email:
27
27
  - whoisdanieldavey@gmail.com
@@ -43,6 +43,9 @@ files:
43
43
  - app_drone.gemspec~
44
44
  - lib/app_drone.rb
45
45
  - lib/app_drone.rb~
46
+ - lib/app_drone/dependency.rb~
47
+ - lib/app_drone/dependency_chain.rb
48
+ - lib/app_drone/dependency_chain.rb~
46
49
  - lib/app_drone/drone.rb
47
50
  - lib/app_drone/drone.rb~
48
51
  - lib/app_drone/drones/bootstrap/bootstrap.rb