app_drone 0.5.2 → 0.6.0

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/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